]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libgo: Update to go1.6rc1.
authorIan Lance Taylor <iant@google.com>
Wed, 3 Feb 2016 21:58:02 +0000 (21:58 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Wed, 3 Feb 2016 21:58:02 +0000 (21:58 +0000)
    Reviewed-on: https://go-review.googlesource.com/19200

From-SVN: r233110

728 files changed:
gotools/ChangeLog
gotools/Makefile.am
gotools/Makefile.in
libgo/MERGE
libgo/Makefile.am
libgo/Makefile.in
libgo/VERSION
libgo/configure
libgo/configure.ac
libgo/go/archive/tar/common.go
libgo/go/archive/tar/reader.go
libgo/go/archive/tar/reader_test.go
libgo/go/archive/tar/testdata/gnu-multi-hdrs.tar [new file with mode: 0644]
libgo/go/archive/tar/testdata/hdr-only.tar [new file with mode: 0644]
libgo/go/archive/tar/testdata/issue12435.tar [new file with mode: 0644]
libgo/go/archive/tar/testdata/neg-size.tar
libgo/go/archive/tar/testdata/pax-multi-hdrs.tar [new file with mode: 0644]
libgo/go/archive/tar/testdata/pax-path-hdr.tar [new file with mode: 0644]
libgo/go/archive/tar/testdata/ustar-file-reg.tar [new file with mode: 0644]
libgo/go/archive/tar/writer.go
libgo/go/archive/tar/writer_test.go
libgo/go/archive/zip/reader.go
libgo/go/archive/zip/reader_test.go
libgo/go/archive/zip/register.go
libgo/go/archive/zip/struct.go
libgo/go/archive/zip/writer.go
libgo/go/archive/zip/zip_test.go
libgo/go/bufio/bufio.go
libgo/go/bufio/example_test.go
libgo/go/bufio/scan.go
libgo/go/bufio/scan_test.go
libgo/go/bytes/buffer.go
libgo/go/bytes/bytes_test.go
libgo/go/cmd/cgo/ast.go
libgo/go/cmd/cgo/doc.go
libgo/go/cmd/cgo/gcc.go
libgo/go/cmd/cgo/godefs.go
libgo/go/cmd/cgo/main.go
libgo/go/cmd/cgo/out.go
libgo/go/cmd/go/alldocs.go
libgo/go/cmd/go/build.go
libgo/go/cmd/go/discovery.go
libgo/go/cmd/go/doc.go
libgo/go/cmd/go/env.go
libgo/go/cmd/go/generate.go
libgo/go/cmd/go/generate_test.go
libgo/go/cmd/go/get.go
libgo/go/cmd/go/go_test.go
libgo/go/cmd/go/go_unix_test.go [new file with mode: 0644]
libgo/go/cmd/go/help.go
libgo/go/cmd/go/http.go
libgo/go/cmd/go/list.go
libgo/go/cmd/go/main.go
libgo/go/cmd/go/note.go
libgo/go/cmd/go/note_test.go
libgo/go/cmd/go/pkg.go
libgo/go/cmd/go/pkg_test.go
libgo/go/cmd/go/run.go
libgo/go/cmd/go/test.go
libgo/go/cmd/go/testdata/flag_test.go [new file with mode: 0644]
libgo/go/cmd/go/testdata/src/run/bad.go [new file with mode: 0644]
libgo/go/cmd/go/testdata/src/run/good.go [new file with mode: 0644]
libgo/go/cmd/go/testdata/src/run/internal/internal.go [new file with mode: 0644]
libgo/go/cmd/go/testdata/src/run/subdir/internal/private/private.go [new file with mode: 0644]
libgo/go/cmd/go/testdata/src/vend/dir1/dir1.go [new file with mode: 0644]
libgo/go/cmd/go/testdata/src/vend/hello/hello_test.go
libgo/go/cmd/go/testdata/src/vend/hello/hellox_test.go
libgo/go/cmd/go/testdata/src/vend/vendor/vend/dir1/dir2/dir2.go [new file with mode: 0644]
libgo/go/cmd/go/testdata/src/vend/x/x.go
libgo/go/cmd/go/testflag.go
libgo/go/cmd/go/tool.go
libgo/go/cmd/go/vcs.go
libgo/go/cmd/go/vcs_test.go
libgo/go/cmd/go/vendor_test.go
libgo/go/cmd/gofmt/gofmt.go
libgo/go/cmd/gofmt/internal.go [new file with mode: 0644]
libgo/go/cmd/gofmt/long_test.go
libgo/go/cmd/gofmt/testdata/old.golden [deleted file]
libgo/go/cmd/gofmt/testdata/old.input [deleted file]
libgo/go/compress/bzip2/bit_reader.go
libgo/go/compress/bzip2/bzip2_test.go
libgo/go/compress/bzip2/huffman.go
libgo/go/compress/flate/deflate_test.go
libgo/go/compress/flate/fixedhuff.go [deleted file]
libgo/go/compress/flate/flate_test.go
libgo/go/compress/flate/gen.go [deleted file]
libgo/go/compress/flate/inflate.go
libgo/go/compress/flate/reader_test.go
libgo/go/compress/flate/token.go
libgo/go/compress/gzip/gunzip.go
libgo/go/compress/gzip/gunzip_test.go
libgo/go/compress/gzip/gzip.go
libgo/go/compress/lzw/reader.go
libgo/go/compress/lzw/writer_test.go
libgo/go/compress/testdata/Mark.Twain-Tom.Sawyer.txt
libgo/go/compress/testdata/gettysburg.txt [new file with mode: 0644]
libgo/go/compress/zlib/reader.go
libgo/go/compress/zlib/reader_test.go
libgo/go/compress/zlib/writer_test.go
libgo/go/crypto/aes/aes_gcm.go [new file with mode: 0644]
libgo/go/crypto/aes/cipher.go
libgo/go/crypto/aes/cipher_generic.go
libgo/go/crypto/cipher/benchmark_test.go
libgo/go/crypto/cipher/ctr.go
libgo/go/crypto/cipher/ctr_test.go [new file with mode: 0644]
libgo/go/crypto/cipher/example_test.go
libgo/go/crypto/cipher/gcm.go
libgo/go/crypto/cipher/gcm_test.go
libgo/go/crypto/crypto.go
libgo/go/crypto/dsa/dsa.go
libgo/go/crypto/ecdsa/ecdsa.go
libgo/go/crypto/ecdsa/ecdsa_test.go
libgo/go/crypto/elliptic/elliptic.go
libgo/go/crypto/elliptic/elliptic_test.go
libgo/go/crypto/elliptic/p256.go
libgo/go/crypto/elliptic/p256_amd64.go [new file with mode: 0644]
libgo/go/crypto/hmac/hmac.go
libgo/go/crypto/md5/md5.go
libgo/go/crypto/rsa/example_test.go [new file with mode: 0644]
libgo/go/crypto/rsa/pkcs1v15.go
libgo/go/crypto/rsa/pkcs1v15_test.go
libgo/go/crypto/rsa/pss.go
libgo/go/crypto/rsa/rsa.go
libgo/go/crypto/rsa/rsa_test.go
libgo/go/crypto/tls/cipher_suites.go
libgo/go/crypto/tls/common.go
libgo/go/crypto/tls/conn.go
libgo/go/crypto/tls/handshake_client.go
libgo/go/crypto/tls/handshake_client_test.go
libgo/go/crypto/tls/handshake_messages.go
libgo/go/crypto/tls/handshake_server_test.go
libgo/go/crypto/tls/prf.go
libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4
libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4
libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256 [new file with mode: 0644]
libgo/go/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384 [new file with mode: 0644]
libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN
libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384
libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384
libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
libgo/go/crypto/tls/testdata/Client-TLSv12-RSA-RC4
libgo/go/crypto/tls/testdata/Client-TLSv12-SCT
libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-3DES
libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-AES
libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-RC4
libgo/go/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-3DES
libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-AES
libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-RC4
libgo/go/crypto/tls/testdata/Server-TLSv11-FallbackSCSV
libgo/go/crypto/tls/testdata/Server-TLSv11-RSA-RC4
libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN
libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicket
libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-3DES
libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES
libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384
libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-RC4
libgo/go/crypto/tls/testdata/Server-TLSv12-Resume
libgo/go/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
libgo/go/crypto/tls/testdata/Server-TLSv12-SNI
libgo/go/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate
libgo/go/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound
libgo/go/crypto/tls/tls.go
libgo/go/crypto/tls/tls_test.go
libgo/go/crypto/x509/pkix/pkix.go
libgo/go/crypto/x509/root_unix.go
libgo/go/crypto/x509/sec1.go
libgo/go/crypto/x509/sec1_test.go
libgo/go/crypto/x509/verify.go
libgo/go/crypto/x509/x509.go
libgo/go/crypto/x509/x509_test.go
libgo/go/database/sql/convert.go
libgo/go/database/sql/convert_test.go
libgo/go/database/sql/driver/types.go
libgo/go/database/sql/fakedb_test.go
libgo/go/database/sql/sql.go
libgo/go/database/sql/sql_test.go
libgo/go/debug/dwarf/class_string.go
libgo/go/debug/dwarf/entry.go
libgo/go/debug/dwarf/entry_test.go [new file with mode: 0644]
libgo/go/debug/dwarf/testdata/cycle.c [new file with mode: 0644]
libgo/go/debug/dwarf/testdata/cycle.elf [new file with mode: 0644]
libgo/go/debug/dwarf/testdata/split.c [new file with mode: 0644]
libgo/go/debug/dwarf/testdata/split.elf [new file with mode: 0644]
libgo/go/debug/dwarf/type.go
libgo/go/debug/dwarf/type_test.go
libgo/go/debug/dwarf/typeunit.go
libgo/go/debug/elf/elf.go
libgo/go/debug/elf/file.go
libgo/go/debug/elf/file_test.go
libgo/go/debug/elf/reader.go [new file with mode: 0644]
libgo/go/debug/elf/testdata/compressed-32.obj [new file with mode: 0644]
libgo/go/debug/elf/testdata/compressed-64.obj [new file with mode: 0644]
libgo/go/debug/elf/testdata/go-relocation-test-gcc492-mips64.obj [new file with mode: 0644]
libgo/go/debug/elf/testdata/go-relocation-test-gcc493-mips64le.obj [new file with mode: 0644]
libgo/go/debug/elf/testdata/zdebug-test-gcc484-x86-64.obj [new file with mode: 0644]
libgo/go/debug/gosym/pclntab_test.go
libgo/go/encoding/asn1/asn1.go
libgo/go/encoding/asn1/asn1_test.go
libgo/go/encoding/asn1/common.go
libgo/go/encoding/asn1/marshal.go
libgo/go/encoding/base64/base64.go
libgo/go/encoding/base64/base64_test.go
libgo/go/encoding/binary/binary.go
libgo/go/encoding/binary/binary_test.go
libgo/go/encoding/csv/reader.go
libgo/go/encoding/gob/codec_test.go
libgo/go/encoding/gob/dec_helpers.go
libgo/go/encoding/gob/decgen.go
libgo/go/encoding/gob/decode.go
libgo/go/encoding/gob/doc.go
libgo/go/encoding/gob/encode.go
libgo/go/encoding/gob/encoder_test.go
libgo/go/encoding/gob/timing_test.go
libgo/go/encoding/gob/type.go
libgo/go/encoding/json/decode.go
libgo/go/encoding/json/decode_test.go
libgo/go/encoding/json/encode.go
libgo/go/encoding/json/encode_test.go
libgo/go/encoding/json/indent.go
libgo/go/encoding/json/number_test.go [new file with mode: 0644]
libgo/go/encoding/json/scanner.go
libgo/go/encoding/json/stream.go
libgo/go/encoding/pem/pem_test.go
libgo/go/encoding/xml/marshal.go
libgo/go/encoding/xml/marshal_test.go
libgo/go/encoding/xml/read.go
libgo/go/encoding/xml/read_test.go
libgo/go/encoding/xml/typeinfo.go
libgo/go/encoding/xml/xml.go
libgo/go/encoding/xml/xml_test.go
libgo/go/fmt/doc.go
libgo/go/fmt/fmt_test.go
libgo/go/fmt/print.go
libgo/go/fmt/scan.go
libgo/go/fmt/scan_test.go
libgo/go/go/ast/import.go
libgo/go/go/build/build.go
libgo/go/go/build/build_test.go
libgo/go/go/build/deps_test.go
libgo/go/go/build/doc.go
libgo/go/go/constant/go13.go [deleted file]
libgo/go/go/constant/value.go
libgo/go/go/constant/value_test.go
libgo/go/go/doc/reader.go
libgo/go/go/doc/testdata/issue13742.0.golden [new file with mode: 0644]
libgo/go/go/doc/testdata/issue13742.1.golden [new file with mode: 0644]
libgo/go/go/doc/testdata/issue13742.2.golden [new file with mode: 0644]
libgo/go/go/doc/testdata/issue13742.go [new file with mode: 0644]
libgo/go/go/format/format.go
libgo/go/go/format/format_test.go
libgo/go/go/format/internal.go [moved from libgo/go/internal/format/format.go with 81% similarity]
libgo/go/go/importer/importer.go
libgo/go/go/internal/gccgoimporter/importer_test.go
libgo/go/go/internal/gcimporter/bimport.go [new file with mode: 0644]
libgo/go/go/internal/gcimporter/exportdata.go
libgo/go/go/internal/gcimporter/gcimporter.go
libgo/go/go/internal/gcimporter/gcimporter_test.go
libgo/go/go/internal/gcimporter/testdata/a.go [new file with mode: 0644]
libgo/go/go/internal/gcimporter/testdata/b.go [new file with mode: 0644]
libgo/go/go/parser/parser.go
libgo/go/go/parser/short_test.go
libgo/go/go/printer/nodes.go
libgo/go/go/printer/printer.go
libgo/go/go/printer/printer_test.go
libgo/go/go/printer/testdata/expressions.golden
libgo/go/go/printer/testdata/expressions.input
libgo/go/go/printer/testdata/expressions.raw
libgo/go/go/types/api.go
libgo/go/go/types/api_test.go
libgo/go/go/types/assignments.go
libgo/go/go/types/builtins.go
libgo/go/go/types/builtins_test.go
libgo/go/go/types/call.go
libgo/go/go/types/check_test.go
libgo/go/go/types/conversions.go
libgo/go/go/types/decl.go
libgo/go/go/types/eval_test.go
libgo/go/go/types/expr.go
libgo/go/go/types/go11.go [deleted file]
libgo/go/go/types/go12.go [deleted file]
libgo/go/go/types/gotype.go [new file with mode: 0644]
libgo/go/go/types/hilbert_test.go
libgo/go/go/types/issues_test.go
libgo/go/go/types/operand.go
libgo/go/go/types/package.go
libgo/go/go/types/resolver.go
libgo/go/go/types/resolver_test.go
libgo/go/go/types/self_test.go
libgo/go/go/types/sizes.go
libgo/go/go/types/stdlib_test.go
libgo/go/go/types/stmt.go
libgo/go/go/types/type.go
libgo/go/go/types/typestring.go
libgo/go/go/types/typestring_test.go
libgo/go/go/types/typexpr.go
libgo/go/hash/adler32/adler32.go
libgo/go/hash/crc32/crc32.go
libgo/go/hash/crc32/crc32_amd64.go [new file with mode: 0644]
libgo/go/hash/crc32/crc32_amd64p32.go [moved from libgo/go/hash/crc32/crc32_amd64x.go with 62% similarity]
libgo/go/hash/crc32/crc32_generic.go
libgo/go/hash/crc64/crc64.go
libgo/go/hash/fnv/fnv.go
libgo/go/html/escape.go
libgo/go/html/escape_test.go
libgo/go/html/template/clone_test.go
libgo/go/html/template/context.go
libgo/go/html/template/escape_test.go
libgo/go/html/template/example_test.go
libgo/go/html/template/template.go
libgo/go/html/template/template_test.go [new file with mode: 0644]
libgo/go/html/template/transition.go
libgo/go/image/color/ycbcr.go
libgo/go/image/color/ycbcr_test.go
libgo/go/image/draw/draw.go
libgo/go/image/gif/writer.go
libgo/go/image/gif/writer_test.go
libgo/go/image/image.go
libgo/go/image/png/reader.go
libgo/go/image/png/reader_test.go
libgo/go/image/ycbcr.go
libgo/go/internal/golang.org/x/net/http2/hpack/encode.go [new file with mode: 0644]
libgo/go/internal/golang.org/x/net/http2/hpack/encode_test.go [new file with mode: 0644]
libgo/go/internal/golang.org/x/net/http2/hpack/hpack.go [new file with mode: 0644]
libgo/go/internal/golang.org/x/net/http2/hpack/hpack_test.go [new file with mode: 0644]
libgo/go/internal/golang.org/x/net/http2/hpack/huffman.go [new file with mode: 0644]
libgo/go/internal/golang.org/x/net/http2/hpack/tables.go [new file with mode: 0644]
libgo/go/internal/race/doc.go [new file with mode: 0644]
libgo/go/internal/race/norace.go [new file with mode: 0644]
libgo/go/internal/race/race.go [new file with mode: 0644]
libgo/go/internal/syscall/unix/getrandom_linux.go
libgo/go/internal/syscall/unix/getrandom_linux_386.go [new file with mode: 0644]
libgo/go/internal/syscall/unix/getrandom_linux_amd64.go [new file with mode: 0644]
libgo/go/internal/syscall/unix/getrandom_linux_arm.go [new file with mode: 0644]
libgo/go/internal/syscall/unix/getrandom_linux_generic.go [moved from libgo/go/go/constant/go14.go with 57% similarity]
libgo/go/internal/syscall/unix/getrandom_linux_mips64x.go [new file with mode: 0644]
libgo/go/internal/syscall/unix/getrandom_linux_ppc64x.go [new file with mode: 0644]
libgo/go/internal/syscall/windows/registry/registry_test.go
libgo/go/internal/syscall/windows/registry/syscall.go
libgo/go/internal/syscall/windows/registry/value.go
libgo/go/internal/syscall/windows/registry/zsyscall_windows.go
libgo/go/internal/syscall/windows/syscall_windows.go
libgo/go/internal/syscall/windows/zsyscall_windows.go
libgo/go/internal/trace/parser.go
libgo/go/internal/trace/parser_test.go
libgo/go/io/example_test.go [new file with mode: 0644]
libgo/go/io/io.go
libgo/go/io/ioutil/example_test.go [new file with mode: 0644]
libgo/go/io/ioutil/ioutil.go
libgo/go/io/multi.go
libgo/go/io/multi_test.go
libgo/go/log/syslog/doc.go
libgo/go/log/syslog/syslog_test.go
libgo/go/math/abs.go
libgo/go/math/all_test.go
libgo/go/math/big/decimal.go
libgo/go/math/big/decimal_test.go
libgo/go/math/big/doc.go [new file with mode: 0644]
libgo/go/math/big/example_rat_test.go [new file with mode: 0644]
libgo/go/math/big/float.go
libgo/go/math/big/floatconv.go
libgo/go/math/big/floatconv_test.go
libgo/go/math/big/floatexample_test.go
libgo/go/math/big/floatmarsh.go [new file with mode: 0644]
libgo/go/math/big/floatmarsh_test.go [new file with mode: 0644]
libgo/go/math/big/ftoa.go
libgo/go/math/big/int.go
libgo/go/math/big/int_test.go
libgo/go/math/big/intconv.go
libgo/go/math/big/intconv_test.go
libgo/go/math/big/intmarsh.go [new file with mode: 0644]
libgo/go/math/big/intmarsh_test.go [new file with mode: 0644]
libgo/go/math/big/nat.go
libgo/go/math/big/nat_test.go
libgo/go/math/big/natconv.go
libgo/go/math/big/natconv_test.go
libgo/go/math/big/rat.go
libgo/go/math/big/rat_test.go
libgo/go/math/big/ratconv.go
libgo/go/math/big/ratmarsh.go [new file with mode: 0644]
libgo/go/math/big/ratmarsh_test.go [new file with mode: 0644]
libgo/go/math/cmplx/cmath_test.go
libgo/go/math/cmplx/sqrt.go
libgo/go/math/expm1.go
libgo/go/math/floor_asm.go [moved from libgo/go/fmt/race_test.go with 59% similarity]
libgo/go/math/j0.go
libgo/go/math/j1.go
libgo/go/math/jn.go
libgo/go/math/modf.go
libgo/go/math/rand/rand.go
libgo/go/math/rand/rand_test.go
libgo/go/math/rand/regress_test.go
libgo/go/math/sqrt.go
libgo/go/mime/encodedword.go
libgo/go/mime/encodedword_test.go
libgo/go/mime/example_test.go [new file with mode: 0644]
libgo/go/mime/mediatype.go
libgo/go/mime/mediatype_test.go
libgo/go/mime/multipart/multipart.go
libgo/go/mime/multipart/multipart_test.go
libgo/go/net/addrselect.go
libgo/go/net/addrselect_test.go
libgo/go/net/cgo_socknew.go
libgo/go/net/cgo_sockold.go
libgo/go/net/cgo_unix.go
libgo/go/net/conf.go
libgo/go/net/dial.go
libgo/go/net/dial_test.go
libgo/go/net/dnsclient.go
libgo/go/net/dnsclient_test.go
libgo/go/net/dnsclient_unix.go
libgo/go/net/dnsclient_unix_test.go
libgo/go/net/dnsmsg.go
libgo/go/net/error_test.go
libgo/go/net/fd_plan9.go
libgo/go/net/fd_unix.go
libgo/go/net/fd_windows.go
libgo/go/net/file_test.go
libgo/go/net/file_unix.go
libgo/go/net/hosts.go
libgo/go/net/hosts_test.go
libgo/go/net/http/cgi/host.go
libgo/go/net/http/cgi/host_test.go
libgo/go/net/http/client.go
libgo/go/net/http/client_test.go
libgo/go/net/http/clientserver_test.go [new file with mode: 0644]
libgo/go/net/http/doc.go
libgo/go/net/http/export_test.go
libgo/go/net/http/fcgi/child.go
libgo/go/net/http/fcgi/fcgi_test.go
libgo/go/net/http/fs.go
libgo/go/net/http/fs_test.go
libgo/go/net/http/h2_bundle.go [new file with mode: 0644]
libgo/go/net/http/header.go
libgo/go/net/http/httptest/recorder.go
libgo/go/net/http/httptest/recorder_test.go
libgo/go/net/http/httptest/server.go
libgo/go/net/http/httptest/server_test.go
libgo/go/net/http/httputil/dump.go
libgo/go/net/http/httputil/dump_test.go
libgo/go/net/http/httputil/example_test.go [new file with mode: 0644]
libgo/go/net/http/httputil/reverseproxy.go
libgo/go/net/http/httputil/reverseproxy_test.go
libgo/go/net/http/internal/chunked.go
libgo/go/net/http/internal/chunked_test.go
libgo/go/net/http/internal/testcert.go [new file with mode: 0644]
libgo/go/net/http/lex.go
libgo/go/net/http/main_test.go
libgo/go/net/http/method.go [new file with mode: 0644]
libgo/go/net/http/pprof/pprof.go
libgo/go/net/http/request.go
libgo/go/net/http/request_test.go
libgo/go/net/http/response.go
libgo/go/net/http/response_test.go
libgo/go/net/http/serve_test.go
libgo/go/net/http/server.go
libgo/go/net/http/sniff.go
libgo/go/net/http/sniff_test.go
libgo/go/net/http/status.go
libgo/go/net/http/transfer.go
libgo/go/net/http/transport.go
libgo/go/net/http/transport_test.go
libgo/go/net/http/triv.go
libgo/go/net/interface_test.go
libgo/go/net/interface_windows.go
libgo/go/net/interface_windows_test.go [new file with mode: 0644]
libgo/go/net/internal/socktest/switch.go
libgo/go/net/iprawsock_posix.go
libgo/go/net/ipsock.go
libgo/go/net/ipsock_posix.go
libgo/go/net/lookup.go
libgo/go/net/lookup_plan9.go
libgo/go/net/lookup_test.go
libgo/go/net/lookup_windows.go
libgo/go/net/mac.go
libgo/go/net/mac_test.go
libgo/go/net/mail/message.go
libgo/go/net/mail/message_test.go
libgo/go/net/net.go
libgo/go/net/net_test.go
libgo/go/net/non_unix_test.go
libgo/go/net/parse.go
libgo/go/net/parse_test.go
libgo/go/net/platform_test.go
libgo/go/net/port.go [deleted file]
libgo/go/net/port_test.go [deleted file]
libgo/go/net/race.go [deleted file]
libgo/go/net/race0.go [deleted file]
libgo/go/net/rpc/server.go
libgo/go/net/rpc/server_test.go
libgo/go/net/sendfile_solaris.go
libgo/go/net/server_test.go
libgo/go/net/sock_posix.go
libgo/go/net/tcp_test.go
libgo/go/net/tcpsock_plan9.go
libgo/go/net/tcpsock_posix.go
libgo/go/net/tcpsockopt_plan9.go
libgo/go/net/testdata/case-hosts [new file with mode: 0644]
libgo/go/net/testdata/hosts
libgo/go/net/textproto/reader.go
libgo/go/net/textproto/reader_test.go
libgo/go/net/timeout_test.go
libgo/go/net/udpsock_posix.go
libgo/go/net/unix_test.go
libgo/go/net/unixsock_posix.go
libgo/go/net/url/url.go
libgo/go/net/url/url_test.go
libgo/go/os/error.go
libgo/go/os/error_plan9.go
libgo/go/os/error_test.go
libgo/go/os/error_unix.go
libgo/go/os/error_windows.go
libgo/go/os/exec/exec.go
libgo/go/os/exec/exec_test.go
libgo/go/os/exec/internal_test.go [new file with mode: 0644]
libgo/go/os/file.go
libgo/go/os/file_plan9.go
libgo/go/os/file_unix.go
libgo/go/os/os_test.go
libgo/go/os/os_unix_test.go
libgo/go/os/path_test.go
libgo/go/os/pipe_test.go [new file with mode: 0644]
libgo/go/os/signal/doc.go [new file with mode: 0644]
libgo/go/os/signal/signal.go
libgo/go/os/signal/signal_test.go
libgo/go/os/signal/signal_unix.go
libgo/go/os/stat_atim.go
libgo/go/os/stat_atimespec.go
libgo/go/os/stat_dragonfly.go
libgo/go/os/stat_nacl.go
libgo/go/os/stat_solaris.go
libgo/go/os/types_plan9.go [moved from libgo/go/os/types_notwin.go with 93% similarity]
libgo/go/os/types_unix.go [new file with mode: 0644]
libgo/go/path/filepath/example_unix_test.go
libgo/go/path/filepath/match_test.go
libgo/go/path/filepath/path.go
libgo/go/path/filepath/path_plan9.go
libgo/go/path/filepath/path_test.go
libgo/go/path/filepath/path_unix.go
libgo/go/path/filepath/path_windows.go
libgo/go/path/filepath/symlink.go
libgo/go/path/filepath/symlink_windows.go
libgo/go/path/path.go
libgo/go/reflect/all_test.go
libgo/go/reflect/deepequal.go
libgo/go/reflect/type.go
libgo/go/reflect/value.go
libgo/go/regexp/all_test.go
libgo/go/regexp/onepass.go
libgo/go/regexp/onepass_test.go
libgo/go/regexp/regexp.go
libgo/go/regexp/syntax/parse.go
libgo/go/regexp/syntax/parse_test.go
libgo/go/regexp/syntax/regexp.go
libgo/go/regexp/syntax/simplify_test.go
libgo/go/regexp/testdata/re2-search.txt
libgo/go/runtime/cgo_mmap.go [new file with mode: 0644]
libgo/go/runtime/cgo_ppc64x.go [new file with mode: 0644]
libgo/go/runtime/cgocheck.go [new file with mode: 0644]
libgo/go/runtime/crash_cgo_test.go
libgo/go/runtime/crash_test.go
libgo/go/runtime/crash_unix_test.go
libgo/go/runtime/debug.go
libgo/go/runtime/debug/garbage.go
libgo/go/runtime/debug/garbage_test.go
libgo/go/runtime/debug/heapdump_test.go
libgo/go/runtime/debug/stack.go
libgo/go/runtime/debug/stack_test.go
libgo/go/runtime/defs_linux_mips64x.go [new file with mode: 0644]
libgo/go/runtime/export_test.go
libgo/go/runtime/export_windows_test.go
libgo/go/runtime/extern.go
libgo/go/runtime/fastlog2.go [new file with mode: 0644]
libgo/go/runtime/fastlog2_test.go [new file with mode: 0644]
libgo/go/runtime/fastlog2table.go [new file with mode: 0644]
libgo/go/runtime/gc_test.go
libgo/go/runtime/gcinfo_test.go
libgo/go/runtime/lfstack_linux_mips64x.go [new file with mode: 0644]
libgo/go/runtime/malloc_test.go
libgo/go/runtime/mkfastlog2table.go [new file with mode: 0644]
libgo/go/runtime/mmap.go [new file with mode: 0644]
libgo/go/runtime/msan.go [new file with mode: 0644]
libgo/go/runtime/msan/msan.go [new file with mode: 0644]
libgo/go/runtime/msan0.go [new file with mode: 0644]
libgo/go/runtime/mstkbar.go [new file with mode: 0644]
libgo/go/runtime/os1_linux_generic.go [new file with mode: 0644]
libgo/go/runtime/os1_linux_mips64x.go [new file with mode: 0644]
libgo/go/runtime/os2_linux_generic.go [new file with mode: 0644]
libgo/go/runtime/os2_linux_mips64x.go [new file with mode: 0644]
libgo/go/runtime/os_android.go [new file with mode: 0644]
libgo/go/runtime/os_linux_mips64x.go [new file with mode: 0644]
libgo/go/runtime/pprof/mprof_test.go
libgo/go/runtime/pprof/pprof.go
libgo/go/runtime/pprof/pprof_test.go
libgo/go/runtime/print.go [new file with mode: 0644]
libgo/go/runtime/proc_test.go
libgo/go/runtime/race/testdata/issue12225_test.go [new file with mode: 0644]
libgo/go/runtime/race/testdata/issue12664_test.go [new file with mode: 0644]
libgo/go/runtime/race/testdata/issue13264_test.go [new file with mode: 0644]
libgo/go/runtime/runtime_test.go
libgo/go/runtime/signal2_unix.go [new file with mode: 0644]
libgo/go/runtime/signal_linux_mips64x.go [new file with mode: 0644]
libgo/go/runtime/signal_mips64x.go [new file with mode: 0644]
libgo/go/runtime/signal_sigtramp.go [new file with mode: 0644]
libgo/go/runtime/sigtab_linux_generic.go [new file with mode: 0644]
libgo/go/runtime/sigtab_linux_mips64x.go [new file with mode: 0644]
libgo/go/runtime/stack.go [new file with mode: 0644]
libgo/go/runtime/string_test.go
libgo/go/runtime/sys_mips64x.go [new file with mode: 0644]
libgo/go/runtime/sys_nonppc64x.go [moved from libgo/go/fmt/norace_test.go with 67% similarity]
libgo/go/runtime/testdata/testprog/crash.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprog/deadlock.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprog/gc.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprog/main.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprog/misc.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprog/signal.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprog/stringconcat.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprog/syscall_windows.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprogcgo/callback.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprogcgo/cgo.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprogcgo/crash.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprogcgo/dll_windows.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprogcgo/dropm.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprogcgo/dropm_stub.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprogcgo/exec.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprogcgo/main.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprogcgo/threadpanic.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprogcgo/threadprof.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprogcgo/windows/win.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprognet/main.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprognet/net.go [new file with mode: 0644]
libgo/go/runtime/testdata/testprognet/signal.go [new file with mode: 0644]
libgo/go/runtime/write_err.go [new file with mode: 0644]
libgo/go/runtime/write_err_android.go [new file with mode: 0644]
libgo/go/sort/example_multi_test.go
libgo/go/sort/search.go
libgo/go/sort/sort.go
libgo/go/strconv/ftoa.go
libgo/go/strconv/ftoa_test.go
libgo/go/strconv/isprint.go
libgo/go/strconv/itoa.go
libgo/go/strconv/makeisprint.go
libgo/go/strconv/quote.go
libgo/go/strconv/quote_test.go
libgo/go/strings/example_test.go
libgo/go/strings/strings.go
libgo/go/strings/strings_amd64.go [new file with mode: 0644]
libgo/go/strings/strings_generic.go [new file with mode: 0644]
libgo/go/strings/strings_test.go
libgo/go/sync/cond.go
libgo/go/sync/export_test.go
libgo/go/sync/mutex.go
libgo/go/sync/pool.go
libgo/go/sync/race.go [deleted file]
libgo/go/sync/race0.go [deleted file]
libgo/go/sync/rwmutex.go
libgo/go/sync/waitgroup.go
libgo/go/sync/waitgroup_test.go
libgo/go/syscall/errors_plan9.go
libgo/go/syscall/exec_bsd.go
libgo/go/syscall/exec_linux.go
libgo/go/syscall/exec_linux_test.go
libgo/go/syscall/exec_unix.go
libgo/go/syscall/libcall_bsd.go
libgo/go/syscall/libcall_linux.go
libgo/go/syscall/msan.go [new file with mode: 0644]
libgo/go/syscall/msan0.go [new file with mode: 0644]
libgo/go/syscall/race0.go [deleted file]
libgo/go/syscall/route_bsd.go
libgo/go/syscall/route_bsd_test.go
libgo/go/syscall/sockcmsg_unix.go
libgo/go/syscall/syscall.go
libgo/go/syscall/syscall_linux_mips64x.go [new file with mode: 0644]
libgo/go/syscall/syscall_linux_test.go
libgo/go/syscall/syscall_unix.go
libgo/go/testing/benchmark.go
libgo/go/testing/quick/quick.go
libgo/go/testing/quick/quick_test.go
libgo/go/testing/testing.go
libgo/go/text/scanner/scanner.go
libgo/go/text/template/doc.go
libgo/go/text/template/exec.go
libgo/go/text/template/exec_test.go
libgo/go/text/template/funcs.go
libgo/go/text/template/multi_test.go
libgo/go/text/template/parse/lex.go
libgo/go/text/template/parse/lex_test.go
libgo/go/text/template/parse/parse.go
libgo/go/text/template/parse/parse_test.go
libgo/go/text/template/template.go
libgo/go/time/format.go
libgo/go/time/format_test.go
libgo/go/time/time.go
libgo/go/time/time_test.go
libgo/go/time/zoneinfo.go
libgo/go/time/zoneinfo_windows.go
libgo/go/unicode/example_test.go [new file with mode: 0644]
libgo/go/unicode/tables.go
libgo/go/unicode/utf8/utf8.go
libgo/go/unicode/utf8/utf8_test.go
libgo/runtime/go-signal.c
libgo/runtime/runtime.c
libgo/runtime/runtime.h
libgo/runtime/signal_unix.c

index 5ddd685a9cb7a693d477a139693fa30f442c1834..2d2d042ed6c840280e6c8783faf4c0b189548783 100644 (file)
@@ -1,3 +1,9 @@
+2016-02-03  Ian Lance Taylor  <iant@google.com>
+
+       * Makefile.am (go_cmd_gofmt_files): Update to Go 1.6rc1 by adding
+       internal.go.
+       * Makefile.in: Rebuild.
+
 2015-12-02  Ian Lance Taylor  <iant@google.com>
 
        PR go/66147
index 30c280e62726429cbcc0d9d9e352c3f11157b261..48d7c0d102556bf633f5f81b06cdae399503dddd 100644 (file)
@@ -76,6 +76,7 @@ go_cmd_go_files = \
 go_cmd_gofmt_files = \
        $(cmdsrcdir)/gofmt/doc.go \
        $(cmdsrcdir)/gofmt/gofmt.go \
+       $(cmdsrcdir)/gofmt/internal.go \
        $(cmdsrcdir)/gofmt/rewrite.go \
        $(cmdsrcdir)/gofmt/simplify.go
 
index 54409cd9baf4b761f9bb8b40e0bc0d276a4787ac..f4793514c5384c858bafe39e6561df72e8f2fe55 100644 (file)
@@ -294,6 +294,7 @@ go_cmd_go_files = \
 go_cmd_gofmt_files = \
        $(cmdsrcdir)/gofmt/doc.go \
        $(cmdsrcdir)/gofmt/gofmt.go \
+       $(cmdsrcdir)/gofmt/internal.go \
        $(cmdsrcdir)/gofmt/rewrite.go \
        $(cmdsrcdir)/gofmt/simplify.go
 
@@ -563,8 +564,8 @@ distclean-generic:
 maintainer-clean-generic:
        @echo "This command is intended for maintainers to use"
        @echo "it deletes files that may require special tools to rebuild."
-@NATIVE_FALSE@install-exec-local:
 @NATIVE_FALSE@uninstall-local:
+@NATIVE_FALSE@install-exec-local:
 clean: clean-am
 
 clean-am: clean-binPROGRAMS clean-generic clean-noinstPROGRAMS \
index ea32fc1cfb08ef7a4a16b9d3b90b750eb823ab2d..0522f32c87b13da938d04a8b3359eb310b58d1d0 100644 (file)
@@ -1,4 +1,4 @@
-f2e4c8b5fb3660d793b2c545ef207153db0a34b1
+036b8fd40b60830ca1d152f17148e52b96d8aa6c
 
 The first line of this file holds the git revision number of the
 last merge done from the master library sources.
index bf26a4cb667171107ef861743f4e7e184d91b6d3..bae3634cff52209696c5901635f4167d7be2c7be 100644 (file)
@@ -846,9 +846,7 @@ go_net_common_files = \
        go/net/parse.go \
        go/net/pipe.go \
        go/net/fd_poll_runtime.go \
-       go/net/port.go \
        go/net/port_unix.go \
-       go/net/race0.go \
        $(go_net_sendfile_file) \
        go/net/sock_posix.go \
        $(go_net_sock_file) \
@@ -1018,7 +1016,7 @@ go_os_files = \
        $(go_os_sys_file) \
        $(go_os_cloexec_file) \
        go/os/types.go \
-       go/os/types_notwin.go
+       go/os/types_unix.go
 
 go_path_files = \
        go/path/match.go \
@@ -1100,7 +1098,8 @@ go_strings_files = \
        go/strings/replace.go \
        go/strings/search.go \
        go/strings/strings.go \
-       go/strings/strings_decl.go
+       go/strings/strings_decl.go \
+       go/strings/strings_generic.go
 go_strings_c_files = \
        go/strings/indexbyte.c
 
@@ -1109,7 +1108,6 @@ go_sync_files = \
        go/sync/mutex.go \
        go/sync/once.go \
        go/sync/pool.go \
-       go/sync/race0.go \
        go/sync/runtime.go \
        go/sync/rwmutex.go \
        go/sync/waitgroup.go
@@ -1196,7 +1194,6 @@ go_compress_bzip2_files = \
 go_compress_flate_files = \
        go/compress/flate/copy.go \
        go/compress/flate/deflate.go \
-       go/compress/flate/fixedhuff.go \
        go/compress/flate/huffman_bit_writer.go \
        go/compress/flate/huffman_code.go \
        go/compress/flate/inflate.go \
@@ -1367,7 +1364,8 @@ go_debug_dwarf_files = \
        go/debug/dwarf/unit.go
 go_debug_elf_files = \
        go/debug/elf/elf.go \
-       go/debug/elf/file.go
+       go/debug/elf/file.go \
+       go/debug/elf/reader.go
 go_debug_gosym_files = \
        go/debug/gosym/pclntab.go \
        go/debug/gosym/symtab.go
@@ -1450,7 +1448,6 @@ go_go_build_files = \
        go/go/build/read.go \
        go/go/build/syslist.go
 go_go_constant_files = \
-       go/go/constant/go14.go \
        go/go/constant/value.go
 go_go_doc_files = \
        go/go/doc/comment.go \
@@ -1461,7 +1458,8 @@ go_go_doc_files = \
        go/go/doc/reader.go \
        go/go/doc/synopsis.go
 go_go_format_files = \
-       go/go/format/format.go
+       go/go/format/format.go \
+       go/go/format/internal.go
 go_go_importer_files = \
        go/go/importer/importer.go
 go_go_parser_files = \
@@ -1489,7 +1487,6 @@ go_go_types_files = \
        go/go/types/eval.go \
        go/go/types/expr.go \
        go/go/types/exprstring.go \
-       go/go/types/go12.go \
        go/go/types/initorder.go \
        go/go/types/labels.go \
        go/go/types/lookup.go \
@@ -1512,6 +1509,7 @@ go_go_types_files = \
        go/go/types/universe.go
 
 go_go_internal_gcimporter_files = \
+       go/go/internal/gcimporter/bimport.go \
        go/go/internal/gcimporter/exportdata.go \
        go/go/internal/gcimporter/gcimporter.go
 go_go_internal_gccgoimporter_files = \
@@ -1578,20 +1576,46 @@ go_index_suffixarray_files = \
        go/index/suffixarray/qsufsort.go \
        go/index/suffixarray/suffixarray.go
 
-go_internal_format_files = \
-       go/internal/format/format.go
+go_internal_golang_org_x_net_http2_hpack_files = \
+       go/internal/golang.org/x/net/http2/hpack/encode.go \
+       go/internal/golang.org/x/net/http2/hpack/hpack.go \
+       go/internal/golang.org/x/net/http2/hpack/huffman.go \
+       go/internal/golang.org/x/net/http2/hpack/tables.go
+go_internal_race_files = \
+       go/internal/race/doc.go \
+       go/internal/race/norace.go
 go_internal_singleflight_files = \
        go/internal/singleflight/singleflight.go
 
 if LIBGO_IS_LINUX
-internal_syscall_unix_getrandom_file = go/internal/syscall/unix/getrandom_linux.go
+if LIBGO_IS_386
+internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_386.go
+else
+if LIBGO_IS_X86_64
+internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_amd64.go
+else
+if LIBGO_IS_ARM
+internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_arm.go
+else
+if LIBGO_IS_PPC64
+internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_ppc64x.go
 else
-internal_syscall_unix_getrandom_file =
+if LIBGO_IS_MIPS64
+internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_mips64x.go
+else
+internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_generic.go
+endif
+endif
+endif
+endif
+endif
+else
+internal_syscall_unix_getrandom_files =
 endif
 
 go_internal_syscall_unix_files = \
        go/internal/syscall/unix/dummy.go \
-       $(internal_syscall_unix_getrandom_file)
+       $(internal_syscall_unix_getrandom_files)
 
 go_internal_testenv_files = \
        go/internal/testenv/testenv.go
@@ -1608,15 +1632,19 @@ go_math_big_files = \
        go/math/big/arith.go \
        go/math/big/arith_decl_pure.go \
        go/math/big/decimal.go \
+       go/math/big/doc.go \
        go/math/big/float.go \
        go/math/big/floatconv.go \
+       go/math/big/floatmarsh.go \
        go/math/big/ftoa.go \
        go/math/big/int.go \
+       go/math/big/intmarsh.go \
        go/math/big/intconv.go \
        go/math/big/nat.go \
        go/math/big/natconv.go \
        go/math/big/rat.go \
        go/math/big/ratconv.go \
+       go/math/big/ratmarsh.go \
        go/math/big/roundingmode_string.go
 go_math_cmplx_files = \
        go/math/cmplx/abs.go \
@@ -1654,9 +1682,11 @@ go_net_http_files = \
        go/net/http/cookie.go \
        go/net/http/filetransport.go \
        go/net/http/fs.go \
+       go/net/http/h2_bundle.go \
        go/net/http/header.go \
        go/net/http/jar.go \
        go/net/http/lex.go \
+       go/net/http/method.go \
        go/net/http/request.go \
        go/net/http/response.go \
        go/net/http/server.go \
@@ -1698,7 +1728,8 @@ go_net_http_httputil_files = \
        go/net/http/httputil/persist.go \
        go/net/http/httputil/reverseproxy.go
 go_net_http_internal_files = \
-       go/net/http/internal/chunked.go
+       go/net/http/internal/chunked.go \
+       go/net/http/internal/testcert.go
 
 if LIBGO_IS_LINUX
 go_net_internal_socktest_sys = go/net/internal/socktest/sys_cloexec.go
@@ -1731,6 +1762,7 @@ go_os_exec_files = \
        go/os/exec/lp_unix.go
 
 go_os_signal_files = \
+       go/os/signal/doc.go \
        go/os/signal/signal.go \
        go/os/signal/signal_unix.go
 
@@ -1999,7 +2031,7 @@ go_base_syscall_files = \
        go/syscall/syscall_errno.go \
        go/syscall/libcall_support.go \
        go/syscall/libcall_posix.go \
-       go/syscall/race0.go \
+       go/syscall/msan0.go \
        go/syscall/socket.go \
        go/syscall/sockcmsg_unix.go \
        go/syscall/str.go \
@@ -2229,7 +2261,8 @@ libgo_go_objs = \
        image/jpeg.lo \
        image/png.lo \
        index/suffixarray.lo \
-       internal/format.lo \
+       internal/golang.org/x/net/http2/hpack.lo \
+       internal/race.lo \
        internal/singleflight.lo \
        internal/syscall/unix.lo \
        internal/testenv.lo \
@@ -2358,7 +2391,7 @@ CHECK = \
        elif test "$(GOBENCH)" != ""; then \
          $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" --bench="$(GOBENCH)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files); \
        else \
-         if $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files) >>$@-testlog 2>&1; then \
+         if $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst .,_,$(subst /,_,$(@D)))_files)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files) >>$@-testlog 2>&1; then \
            echo "PASS: $(@D)" >> $@-testlog; \
            echo "PASS: $(@D)"; \
            echo "PASS: $(@D)" > $@-testsum; \
@@ -3350,14 +3383,23 @@ index/suffixarray/check: $(CHECK_DEPS)
        @$(CHECK)
 .PHONY: index/suffixarray/check
 
-@go_include@ internal/format.lo.dep
-internal/format.lo.dep: $(go_internal_format_files)
+@go_include@ internal/golang.org/x/net/http2/hpack.lo.dep
+internal/golang.org/x/net/http2/hpack.lo.dep: $(go_internal_golang_org_x_net_http2_hpack_files)
+       $(BUILDDEPS)
+internal/golang.org/x/net/http2/hpack.lo: $(go_internal_golang_org_x_net_http2_hpack_files)
+       $(BUILDPACKAGE)
+internal/golang.org/x/net/http2/hpack/check: $(CHECK_DEPS)
+       @$(CHECK)
+.PHONY: internal/golang.org/x/net/http2/hpack/check
+
+@go_include@ internal/race.lo.dep
+internal/race.lo.dep: $(go_internal_race_files)
        $(BUILDDEPS)
-internal/format.lo: $(go_internal_format_files)
+internal/race.lo: $(go_internal_race_files)
        $(BUILDPACKAGE)
-internal/format/check: $(CHECK_DEPS)
+internal/race/check: $(CHECK_DEPS)
        @$(CHECK)
-.PHONY: internal/format/check
+.PHONY: internal/race/check
 
 @go_include@ internal/singleflight.lo.dep
 internal/singleflight.lo.dep: $(go_internal_singleflight_files)
@@ -4013,7 +4055,9 @@ image/color/palette.gox: image/color/palette.lo
 index/suffixarray.gox: index/suffixarray.lo
        $(BUILDGOX)
 
-internal/format.gox: internal/format.lo
+internal/golang.org/x/net/http2/hpack.gox: internal/golang.org/x/net/http2/hpack.lo
+       $(BUILDGOX)
+internal/race.gox: internal/race.lo
        $(BUILDGOX)
 internal/singleflight.gox: internal/singleflight.lo
        $(BUILDGOX)
@@ -4217,6 +4261,7 @@ TEST_PACKAGES = \
        image/jpeg/check \
        image/png/check \
        index/suffixarray/check \
+       internal/golang.org/x/net/http2/hpack/check \
        internal/singleflight/check \
        internal/trace/check \
        io/ioutil/check \
index bcfed74b9271865a41269910201248d062baae6a..216ab6a9b1f2697d7bc81e6d983ad8f51cb788a5 100644 (file)
@@ -205,7 +205,8 @@ am__DEPENDENCIES_2 = bufio.lo bytes.lo bytes/index.lo crypto.lo \
        net/http/httputil.lo net/http/internal.lo net/http/pprof.lo \
        image/color.lo image/color/palette.lo image/draw.lo \
        image/gif.lo image/internal/imageutil.lo image/jpeg.lo \
-       image/png.lo index/suffixarray.lo internal/format.lo \
+       image/png.lo index/suffixarray.lo \
+       internal/golang.org/x/net/http2/hpack.lo internal/race.lo \
        internal/singleflight.lo internal/syscall/unix.lo \
        internal/testenv.lo internal/trace.lo io/ioutil.lo \
        log/syslog.lo log/syslog/syslog_c.lo math/big.lo math/cmplx.lo \
@@ -1129,9 +1130,7 @@ go_net_common_files = \
        go/net/parse.go \
        go/net/pipe.go \
        go/net/fd_poll_runtime.go \
-       go/net/port.go \
        go/net/port_unix.go \
-       go/net/race0.go \
        $(go_net_sendfile_file) \
        go/net/sock_posix.go \
        $(go_net_sock_file) \
@@ -1216,7 +1215,7 @@ go_os_files = \
        $(go_os_sys_file) \
        $(go_os_cloexec_file) \
        go/os/types.go \
-       go/os/types_notwin.go
+       go/os/types_unix.go
 
 go_path_files = \
        go/path/match.go \
@@ -1274,7 +1273,8 @@ go_strings_files = \
        go/strings/replace.go \
        go/strings/search.go \
        go/strings/strings.go \
-       go/strings/strings_decl.go
+       go/strings/strings_decl.go \
+       go/strings/strings_generic.go
 
 go_strings_c_files = \
        go/strings/indexbyte.c
@@ -1284,7 +1284,6 @@ go_sync_files = \
        go/sync/mutex.go \
        go/sync/once.go \
        go/sync/pool.go \
-       go/sync/race0.go \
        go/sync/runtime.go \
        go/sync/rwmutex.go \
        go/sync/waitgroup.go
@@ -1352,7 +1351,6 @@ go_compress_bzip2_files = \
 go_compress_flate_files = \
        go/compress/flate/copy.go \
        go/compress/flate/deflate.go \
-       go/compress/flate/fixedhuff.go \
        go/compress/flate/huffman_bit_writer.go \
        go/compress/flate/huffman_code.go \
        go/compress/flate/inflate.go \
@@ -1511,7 +1509,8 @@ go_debug_dwarf_files = \
 
 go_debug_elf_files = \
        go/debug/elf/elf.go \
-       go/debug/elf/file.go
+       go/debug/elf/file.go \
+       go/debug/elf/reader.go
 
 go_debug_gosym_files = \
        go/debug/gosym/pclntab.go \
@@ -1611,7 +1610,6 @@ go_go_build_files = \
        go/go/build/syslist.go
 
 go_go_constant_files = \
-       go/go/constant/go14.go \
        go/go/constant/value.go
 
 go_go_doc_files = \
@@ -1624,7 +1622,8 @@ go_go_doc_files = \
        go/go/doc/synopsis.go
 
 go_go_format_files = \
-       go/go/format/format.go
+       go/go/format/format.go \
+       go/go/format/internal.go
 
 go_go_importer_files = \
        go/go/importer/importer.go
@@ -1658,7 +1657,6 @@ go_go_types_files = \
        go/go/types/eval.go \
        go/go/types/expr.go \
        go/go/types/exprstring.go \
-       go/go/types/go12.go \
        go/go/types/initorder.go \
        go/go/types/labels.go \
        go/go/types/lookup.go \
@@ -1681,6 +1679,7 @@ go_go_types_files = \
        go/go/types/universe.go
 
 go_go_internal_gcimporter_files = \
+       go/go/internal/gcimporter/bimport.go \
        go/go/internal/gcimporter/exportdata.go \
        go/go/internal/gcimporter/gcimporter.go
 
@@ -1751,17 +1750,29 @@ go_index_suffixarray_files = \
        go/index/suffixarray/qsufsort.go \
        go/index/suffixarray/suffixarray.go
 
-go_internal_format_files = \
-       go/internal/format/format.go
+go_internal_golang_org_x_net_http2_hpack_files = \
+       go/internal/golang.org/x/net/http2/hpack/encode.go \
+       go/internal/golang.org/x/net/http2/hpack/hpack.go \
+       go/internal/golang.org/x/net/http2/hpack/huffman.go \
+       go/internal/golang.org/x/net/http2/hpack/tables.go
+
+go_internal_race_files = \
+       go/internal/race/doc.go \
+       go/internal/race/norace.go
 
 go_internal_singleflight_files = \
        go/internal/singleflight/singleflight.go
 
-@LIBGO_IS_LINUX_FALSE@internal_syscall_unix_getrandom_file = 
-@LIBGO_IS_LINUX_TRUE@internal_syscall_unix_getrandom_file = go/internal/syscall/unix/getrandom_linux.go
+@LIBGO_IS_386_FALSE@@LIBGO_IS_ARM_FALSE@@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_MIPS64_FALSE@@LIBGO_IS_PPC64_FALSE@@LIBGO_IS_X86_64_FALSE@internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_generic.go
+@LIBGO_IS_386_FALSE@@LIBGO_IS_ARM_FALSE@@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_MIPS64_TRUE@@LIBGO_IS_PPC64_FALSE@@LIBGO_IS_X86_64_FALSE@internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_mips64x.go
+@LIBGO_IS_386_FALSE@@LIBGO_IS_ARM_FALSE@@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_PPC64_TRUE@@LIBGO_IS_X86_64_FALSE@internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_ppc64x.go
+@LIBGO_IS_386_FALSE@@LIBGO_IS_ARM_TRUE@@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_X86_64_FALSE@internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_arm.go
+@LIBGO_IS_386_FALSE@@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_X86_64_TRUE@internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_amd64.go
+@LIBGO_IS_386_TRUE@@LIBGO_IS_LINUX_TRUE@internal_syscall_unix_getrandom_files = go/internal/syscall/unix/getrandom_linux.go go/internal/syscall/unix/getrandom_linux_386.go
+@LIBGO_IS_LINUX_FALSE@internal_syscall_unix_getrandom_files = 
 go_internal_syscall_unix_files = \
        go/internal/syscall/unix/dummy.go \
-       $(internal_syscall_unix_getrandom_file)
+       $(internal_syscall_unix_getrandom_files)
 
 go_internal_testenv_files = \
        go/internal/testenv/testenv.go
@@ -1779,15 +1790,19 @@ go_math_big_files = \
        go/math/big/arith.go \
        go/math/big/arith_decl_pure.go \
        go/math/big/decimal.go \
+       go/math/big/doc.go \
        go/math/big/float.go \
        go/math/big/floatconv.go \
+       go/math/big/floatmarsh.go \
        go/math/big/ftoa.go \
        go/math/big/int.go \
+       go/math/big/intmarsh.go \
        go/math/big/intconv.go \
        go/math/big/nat.go \
        go/math/big/natconv.go \
        go/math/big/rat.go \
        go/math/big/ratconv.go \
+       go/math/big/ratmarsh.go \
        go/math/big/roundingmode_string.go
 
 go_math_cmplx_files = \
@@ -1827,9 +1842,11 @@ go_net_http_files = \
        go/net/http/cookie.go \
        go/net/http/filetransport.go \
        go/net/http/fs.go \
+       go/net/http/h2_bundle.go \
        go/net/http/header.go \
        go/net/http/jar.go \
        go/net/http/lex.go \
+       go/net/http/method.go \
        go/net/http/request.go \
        go/net/http/response.go \
        go/net/http/server.go \
@@ -1881,7 +1898,8 @@ go_net_http_httputil_files = \
        go/net/http/httputil/reverseproxy.go
 
 go_net_http_internal_files = \
-       go/net/http/internal/chunked.go
+       go/net/http/internal/chunked.go \
+       go/net/http/internal/testcert.go
 
 @LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@go_net_internal_socktest_sys = 
 @LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_internal_socktest_sys = go/net/internal/socktest/sys_cloexec.go
@@ -1908,6 +1926,7 @@ go_os_exec_files = \
        go/os/exec/lp_unix.go
 
 go_os_signal_files = \
+       go/os/signal/doc.go \
        go/os/signal/signal.go \
        go/os/signal/signal_unix.go
 
@@ -2083,7 +2102,7 @@ go_base_syscall_files = \
        go/syscall/syscall_errno.go \
        go/syscall/libcall_support.go \
        go/syscall/libcall_posix.go \
-       go/syscall/race0.go \
+       go/syscall/msan0.go \
        go/syscall/socket.go \
        go/syscall/sockcmsg_unix.go \
        go/syscall/str.go \
@@ -2253,7 +2272,8 @@ libgo_go_objs = \
        image/jpeg.lo \
        image/png.lo \
        index/suffixarray.lo \
-       internal/format.lo \
+       internal/golang.org/x/net/http2/hpack.lo \
+       internal/race.lo \
        internal/singleflight.lo \
        internal/syscall/unix.lo \
        internal/testenv.lo \
@@ -2378,7 +2398,7 @@ CHECK = \
        elif test "$(GOBENCH)" != ""; then \
          $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" --bench="$(GOBENCH)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files); \
        else \
-         if $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files) >>$@-testlog 2>&1; then \
+         if $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst .,_,$(subst /,_,$(@D)))_files)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files) >>$@-testlog 2>&1; then \
            echo "PASS: $(@D)" >> $@-testlog; \
            echo "PASS: $(@D)"; \
            echo "PASS: $(@D)" > $@-testsum; \
@@ -2511,6 +2531,7 @@ TEST_PACKAGES = \
        image/jpeg/check \
        image/png/check \
        index/suffixarray/check \
+       internal/golang.org/x/net/http2/hpack/check \
        internal/singleflight/check \
        internal/trace/check \
        io/ioutil/check \
@@ -5743,14 +5764,23 @@ index/suffixarray/check: $(CHECK_DEPS)
        @$(CHECK)
 .PHONY: index/suffixarray/check
 
-@go_include@ internal/format.lo.dep
-internal/format.lo.dep: $(go_internal_format_files)
+@go_include@ internal/golang.org/x/net/http2/hpack.lo.dep
+internal/golang.org/x/net/http2/hpack.lo.dep: $(go_internal_golang_org_x_net_http2_hpack_files)
+       $(BUILDDEPS)
+internal/golang.org/x/net/http2/hpack.lo: $(go_internal_golang_org_x_net_http2_hpack_files)
+       $(BUILDPACKAGE)
+internal/golang.org/x/net/http2/hpack/check: $(CHECK_DEPS)
+       @$(CHECK)
+.PHONY: internal/golang.org/x/net/http2/hpack/check
+
+@go_include@ internal/race.lo.dep
+internal/race.lo.dep: $(go_internal_race_files)
        $(BUILDDEPS)
-internal/format.lo: $(go_internal_format_files)
+internal/race.lo: $(go_internal_race_files)
        $(BUILDPACKAGE)
-internal/format/check: $(CHECK_DEPS)
+internal/race/check: $(CHECK_DEPS)
        @$(CHECK)
-.PHONY: internal/format/check
+.PHONY: internal/race/check
 
 @go_include@ internal/singleflight.lo.dep
 internal/singleflight.lo.dep: $(go_internal_singleflight_files)
@@ -6397,7 +6427,9 @@ image/color/palette.gox: image/color/palette.lo
 index/suffixarray.gox: index/suffixarray.lo
        $(BUILDGOX)
 
-internal/format.gox: internal/format.lo
+internal/golang.org/x/net/http2/hpack.gox: internal/golang.org/x/net/http2/hpack.lo
+       $(BUILDGOX)
+internal/race.gox: internal/race.lo
        $(BUILDGOX)
 internal/singleflight.gox: internal/singleflight.lo
        $(BUILDGOX)
index 77af434f110af853a21db3f2317bc0586ecb4bb8..c9b2fc041cdb4ecf17a1038c29c2a34988890177 100644 (file)
@@ -1 +1 @@
-go1.5.1
\ No newline at end of file
+go1.6rc1
\ No newline at end of file
index e024b2f4b6294681f36184008fbd0bc2ad9c6bb0..5d7b46b4ddd6a85be0d95c5a83518af0c4b615cb 100755 (executable)
@@ -646,6 +646,8 @@ LIBGO_IS_PPC64_FALSE
 LIBGO_IS_PPC64_TRUE
 LIBGO_IS_PPC_FALSE
 LIBGO_IS_PPC_TRUE
+LIBGO_IS_MIPS64_FALSE
+LIBGO_IS_MIPS64_TRUE
 LIBGO_IS_MIPSO64_FALSE
 LIBGO_IS_MIPSO64_TRUE
 LIBGO_IS_MIPSN64_FALSE
@@ -11124,7 +11126,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11127 "configure"
+#line 11129 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11230,7 +11232,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11233 "configure"
+#line 11235 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -13884,6 +13886,14 @@ else
   LIBGO_IS_MIPSO64_FALSE=
 fi
 
+ if test $mips_abi = n64 -o $mips_abi = o64; then
+  LIBGO_IS_MIPS64_TRUE=
+  LIBGO_IS_MIPS64_FALSE='#'
+else
+  LIBGO_IS_MIPS64_TRUE='#'
+  LIBGO_IS_MIPS64_FALSE=
+fi
+
  if test $is_ppc = yes; then
   LIBGO_IS_PPC_TRUE=
   LIBGO_IS_PPC_FALSE='#'
@@ -15799,6 +15809,10 @@ if test -z "${LIBGO_IS_MIPSO64_TRUE}" && test -z "${LIBGO_IS_MIPSO64_FALSE}"; th
   as_fn_error "conditional \"LIBGO_IS_MIPSO64\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${LIBGO_IS_MIPS64_TRUE}" && test -z "${LIBGO_IS_MIPS64_FALSE}"; then
+  as_fn_error "conditional \"LIBGO_IS_MIPS64\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${LIBGO_IS_PPC_TRUE}" && test -z "${LIBGO_IS_PPC_FALSE}"; then
   as_fn_error "conditional \"LIBGO_IS_PPC\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
index 6eddb860974dd04f8050eca56a87d7d947f86950..b912129d475f3057d577cf01b76348d1bd6b775a 100644 (file)
@@ -316,6 +316,7 @@ AM_CONDITIONAL(LIBGO_IS_MIPSO32, test $mips_abi = o32)
 AM_CONDITIONAL(LIBGO_IS_MIPSN32, test $mips_abi = n32)
 AM_CONDITIONAL(LIBGO_IS_MIPSN64, test $mips_abi = n64)
 AM_CONDITIONAL(LIBGO_IS_MIPSO64, test $mips_abi = o64)
+AM_CONDITIONAL(LIBGO_IS_MIPS64, test $mips_abi = n64 -o $mips_abi = o64)
 AM_CONDITIONAL(LIBGO_IS_PPC, test $is_ppc = yes)
 AM_CONDITIONAL(LIBGO_IS_PPC64, test $is_ppc64 = yes)
 AM_CONDITIONAL(LIBGO_IS_PPC64LE, test $is_ppc64le = yes)
index c31df062f7ea54577bafe6eb25dfb06ef2a2a55f..36f4e23980930c82f55749aef4e00779527ccb5c 100644 (file)
@@ -327,3 +327,14 @@ func toASCII(s string) string {
        }
        return buf.String()
 }
+
+// isHeaderOnlyType checks if the given type flag is of the type that has no
+// data section even if a size is specified.
+func isHeaderOnlyType(flag byte) bool {
+       switch flag {
+       case TypeLink, TypeSymlink, TypeChar, TypeBlock, TypeDir, TypeFifo:
+               return true
+       default:
+               return false
+       }
+}
index 67daca27a95b4aa9d4968c66bad117165d6e278b..c8cb69a17841b88f1f232ca05e84f53e00287e1f 100644 (file)
@@ -12,6 +12,7 @@ import (
        "errors"
        "io"
        "io/ioutil"
+       "math"
        "os"
        "strconv"
        "strings"
@@ -36,6 +37,10 @@ type Reader struct {
        hdrBuff [blockSize]byte // buffer to use in readHeader
 }
 
+type parser struct {
+       err error // Last error seen
+}
+
 // A numBytesReader is an io.Reader with a numBytes method, returning the number
 // of bytes remaining in the underlying encoded data.
 type numBytesReader interface {
@@ -49,12 +54,36 @@ type regFileReader struct {
        nb int64     // number of unread bytes for current file entry
 }
 
-// A sparseFileReader is a numBytesReader for reading sparse file data from a tar archive.
+// 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
+       rfr   numBytesReader // Reads the sparse-encoded file data
+       sp    []sparseEntry  // The sparse map for the file
+       pos   int64          // Keeps track of file position
+       total int64          // Total size of the file
+}
+
+// A sparseEntry holds a single entry in a sparse file's sparse map.
+//
+// Sparse files are represented using a series of sparseEntrys.
+// Despite the name, a sparseEntry represents an actual data fragment that
+// references data found in the underlying archive stream. All regions not
+// covered by a sparseEntry are logically filled with zeros.
+//
+// For example, if the underlying raw file contains the 10-byte data:
+//     var compactData = "abcdefgh"
+//
+// And the sparse map has the following entries:
+//     var sp = []sparseEntry{
+//             {offset: 2,  numBytes: 5} // Data fragment for [2..7]
+//             {offset: 18, numBytes: 3} // Data fragment for [18..21]
+//     }
+//
+// Then the content of the resulting sparse file with a "real" size of 25 is:
+//     var sparseData = "\x00"*2 + "abcde" + "\x00"*11 + "fgh" + "\x00"*4
+type sparseEntry struct {
+       offset   int64 // Starting position of the fragment
+       numBytes int64 // Length of the fragment
 }
 
 // Keywords for GNU sparse files in a PAX extended header
@@ -88,69 +117,82 @@ func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
 //
 // io.EOF is returned at the end of the input.
 func (tr *Reader) Next() (*Header, error) {
-       var hdr *Header
-       if tr.err == nil {
-               tr.skipUnread()
-       }
        if tr.err != nil {
-               return hdr, tr.err
-       }
-       hdr = tr.readHeader()
-       if hdr == nil {
-               return hdr, tr.err
+               return nil, tr.err
        }
-       // Check for PAX/GNU header.
-       switch hdr.Typeflag {
-       case TypeXHeader:
-               //  PAX extended header
-               headers, err := parsePAX(tr)
-               if err != nil {
-                       return nil, err
-               }
-               // We actually read the whole file,
-               // but this skips alignment padding
-               tr.skipUnread()
+
+       var hdr *Header
+       var extHdrs map[string]string
+
+       // Externally, Next iterates through the tar archive as if it is a series of
+       // files. Internally, the tar format often uses fake "files" to add meta
+       // data that describes the next file. These meta data "files" should not
+       // normally be visible to the outside. As such, this loop iterates through
+       // one or more "header files" until it finds a "normal file".
+loop:
+       for {
+               tr.err = tr.skipUnread()
                if tr.err != nil {
                        return nil, tr.err
                }
+
                hdr = tr.readHeader()
-               if hdr == nil {
+               if tr.err != nil {
                        return nil, tr.err
                }
-               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.
-               realname, err := ioutil.ReadAll(tr)
-               if err != nil {
-                       return nil, err
-               }
-               hdr, err := tr.Next()
-               hdr.Name = cString(realname)
-               return hdr, err
-       case TypeGNULongLink:
-               // We have a GNU long link header.
-               realname, err := ioutil.ReadAll(tr)
-               if err != nil {
-                       return nil, err
+               // Check for PAX/GNU special headers and files.
+               switch hdr.Typeflag {
+               case TypeXHeader:
+                       extHdrs, tr.err = parsePAX(tr)
+                       if tr.err != nil {
+                               return nil, tr.err
+                       }
+                       continue loop // This is a meta header affecting the next header
+               case TypeGNULongName, TypeGNULongLink:
+                       var realname []byte
+                       realname, tr.err = ioutil.ReadAll(tr)
+                       if tr.err != nil {
+                               return nil, tr.err
+                       }
+
+                       // Convert GNU extensions to use PAX headers.
+                       if extHdrs == nil {
+                               extHdrs = make(map[string]string)
+                       }
+                       var p parser
+                       switch hdr.Typeflag {
+                       case TypeGNULongName:
+                               extHdrs[paxPath] = p.parseString(realname)
+                       case TypeGNULongLink:
+                               extHdrs[paxLinkpath] = p.parseString(realname)
+                       }
+                       if p.err != nil {
+                               tr.err = p.err
+                               return nil, tr.err
+                       }
+                       continue loop // This is a meta header affecting the next header
+               default:
+                       mergePAX(hdr, extHdrs)
+
+                       // Check for a PAX format sparse file
+                       sp, err := tr.checkForGNUSparsePAXHeaders(hdr, extHdrs)
+                       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, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size)
+                               if tr.err != nil {
+                                       return nil, tr.err
+                               }
+                       }
+                       break loop // This is a file, so stop
                }
-               hdr, err := tr.Next()
-               hdr.Linkname = cString(realname)
-               return hdr, err
        }
-       return hdr, tr.err
+       return hdr, nil
 }
 
 // checkForGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers. If they are found, then
@@ -321,6 +363,7 @@ func parsePAX(r io.Reader) (map[string]string, error) {
        if err != nil {
                return nil, err
        }
+       sbuf := string(buf)
 
        // For GNU PAX sparse format 0.0 support.
        // This function transforms the sparse format 0.0 headers into sparse format 0.1 headers.
@@ -329,35 +372,17 @@ func parsePAX(r io.Reader) (map[string]string, error) {
        headers := make(map[string]string)
        // Each record is constructed as
        //     "%d %s=%s\n", length, keyword, value
-       for len(buf) > 0 {
-               // or the header was empty to start with.
-               var sp int
-               // The size field ends at the first space.
-               sp = bytes.IndexByte(buf, ' ')
-               if sp == -1 {
-                       return nil, ErrHeader
-               }
-               // Parse the first token as a decimal integer.
-               n, err := strconv.ParseInt(string(buf[:sp]), 10, 0)
-               if err != nil || n < 5 || int64(len(buf)) < n {
-                       return nil, ErrHeader
-               }
-               // Extract everything between the decimal and the n -1 on the
-               // 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.
-               // Everything else is value.
-               eq := bytes.IndexByte(record, '=')
-               if eq == -1 {
+       for len(sbuf) > 0 {
+               key, value, residual, err := parsePAXRecord(sbuf)
+               if err != nil {
                        return nil, ErrHeader
                }
-               key, value := record[:eq], record[eq+1:]
+               sbuf = residual
 
                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.WriteString(value)
                        sparseMap.Write([]byte{','})
                } else {
                        // Normal key. Set the value in the headers map.
@@ -372,9 +397,42 @@ func parsePAX(r io.Reader) (map[string]string, error) {
        return headers, nil
 }
 
-// cString parses bytes as a NUL-terminated C-style string.
+// parsePAXRecord parses the input PAX record string into a key-value pair.
+// If parsing is successful, it will slice off the currently read record and
+// return the remainder as r.
+//
+// A PAX record is of the following form:
+//     "%d %s=%s\n" % (size, key, value)
+func parsePAXRecord(s string) (k, v, r string, err error) {
+       // The size field ends at the first space.
+       sp := strings.IndexByte(s, ' ')
+       if sp == -1 {
+               return "", "", s, ErrHeader
+       }
+
+       // Parse the first token as a decimal integer.
+       n, perr := strconv.ParseInt(s[:sp], 10, 0) // Intentionally parse as native int
+       if perr != nil || n < 5 || int64(len(s)) < n {
+               return "", "", s, ErrHeader
+       }
+
+       // Extract everything between the space and the final newline.
+       rec, nl, rem := s[sp+1:n-1], s[n-1:n], s[n:]
+       if nl != "\n" {
+               return "", "", s, ErrHeader
+       }
+
+       // The first equals separates the key from the value.
+       eq := strings.IndexByte(rec, '=')
+       if eq == -1 {
+               return "", "", s, ErrHeader
+       }
+       return rec[:eq], rec[eq+1:], rem, nil
+}
+
+// parseString parses bytes as a NUL-terminated C-style string.
 // If a NUL byte is not found then the whole slice is returned as a string.
-func cString(b []byte) string {
+func (*parser) parseString(b []byte) string {
        n := 0
        for n < len(b) && b[n] != 0 {
                n++
@@ -382,19 +440,51 @@ func cString(b []byte) string {
        return string(b[0:n])
 }
 
-func (tr *Reader) octal(b []byte) int64 {
-       // Check for binary format first.
+// parseNumeric parses the input as being encoded in either base-256 or octal.
+// This function may return negative numbers.
+// If parsing fails or an integer overflow occurs, err will be set.
+func (p *parser) parseNumeric(b []byte) int64 {
+       // Check for base-256 (binary) format first.
+       // If the first bit is set, then all following bits constitute a two's
+       // complement encoded number in big-endian byte order.
        if len(b) > 0 && b[0]&0x80 != 0 {
-               var x int64
+               // Handling negative numbers relies on the following identity:
+               //      -a-1 == ^a
+               //
+               // If the number is negative, we use an inversion mask to invert the
+               // data bytes and treat the value as an unsigned number.
+               var inv byte // 0x00 if positive or zero, 0xff if negative
+               if b[0]&0x40 != 0 {
+                       inv = 0xff
+               }
+
+               var x uint64
                for i, c := range b {
+                       c ^= inv // Inverts c only if inv is 0xff, otherwise does nothing
                        if i == 0 {
-                               c &= 0x7f // ignore signal bit in first byte
+                               c &= 0x7f // Ignore signal bit in first byte
+                       }
+                       if (x >> 56) > 0 {
+                               p.err = ErrHeader // Integer overflow
+                               return 0
                        }
-                       x = x<<8 | int64(c)
+                       x = x<<8 | uint64(c)
+               }
+               if (x >> 63) > 0 {
+                       p.err = ErrHeader // Integer overflow
+                       return 0
+               }
+               if inv == 0xff {
+                       return ^int64(x)
                }
-               return x
+               return int64(x)
        }
 
+       // Normal case is base-8 (octal) format.
+       return p.parseOctal(b)
+}
+
+func (p *parser) parseOctal(b []byte) int64 {
        // Because unused fields are filled with NULs, we need
        // to skip leading NULs. Fields may also be padded with
        // spaces or NULs.
@@ -405,23 +495,52 @@ func (tr *Reader) octal(b []byte) int64 {
        if len(b) == 0 {
                return 0
        }
-       x, err := strconv.ParseUint(cString(b), 8, 64)
-       if err != nil {
-               tr.err = err
+       x, perr := strconv.ParseUint(p.parseString(b), 8, 64)
+       if perr != nil {
+               p.err = ErrHeader
        }
        return int64(x)
 }
 
-// skipUnread skips any unread bytes in the existing file entry, as well as any alignment padding.
-func (tr *Reader) skipUnread() {
-       nr := tr.numBytes() + tr.pad // number of bytes to skip
+// skipUnread skips any unread bytes in the existing file entry, as well as any
+// alignment padding. It returns io.ErrUnexpectedEOF if any io.EOF is
+// encountered in the data portion; it is okay to hit io.EOF in the padding.
+//
+// Note that this function still works properly even when sparse files are being
+// used since numBytes returns the bytes remaining in the underlying io.Reader.
+func (tr *Reader) skipUnread() error {
+       dataSkip := tr.numBytes()      // Number of data bytes to skip
+       totalSkip := dataSkip + tr.pad // Total 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
+
+       // If possible, Seek to the last byte before the end of the data section.
+       // Do this because Seek is often lazy about reporting errors; this will mask
+       // the fact that the tar stream may be truncated. We can rely on the
+       // io.CopyN done shortly afterwards to trigger any IO errors.
+       var seekSkipped int64 // Number of bytes skipped via Seek
+       if sr, ok := tr.r.(io.Seeker); ok && dataSkip > 1 {
+               // Not all io.Seeker can actually Seek. For example, os.Stdin implements
+               // io.Seeker, but calling Seek always returns an error and performs
+               // no action. Thus, we try an innocent seek to the current position
+               // to see if Seek is really supported.
+               pos1, err := sr.Seek(0, os.SEEK_CUR)
+               if err == nil {
+                       // Seek seems supported, so perform the real Seek.
+                       pos2, err := sr.Seek(dataSkip-1, os.SEEK_CUR)
+                       if err != nil {
+                               tr.err = err
+                               return tr.err
+                       }
+                       seekSkipped = pos2 - pos1
                }
        }
-       _, tr.err = io.CopyN(ioutil.Discard, tr.r, nr)
+
+       var copySkipped int64 // Number of bytes skipped via CopyN
+       copySkipped, tr.err = io.CopyN(ioutil.Discard, tr.r, totalSkip-seekSkipped)
+       if tr.err == io.EOF && seekSkipped+copySkipped < dataSkip {
+               tr.err = io.ErrUnexpectedEOF
+       }
+       return tr.err
 }
 
 func (tr *Reader) verifyChecksum(header []byte) bool {
@@ -429,23 +548,31 @@ func (tr *Reader) verifyChecksum(header []byte) bool {
                return false
        }
 
-       given := tr.octal(header[148:156])
+       var p parser
+       given := p.parseOctal(header[148:156])
        unsigned, signed := checksum(header)
-       return given == unsigned || given == signed
+       return p.err == nil && (given == unsigned || given == signed)
 }
 
+// readHeader reads the next block header and assumes that the underlying reader
+// is already aligned to a block boundary.
+//
+// The err will be set to io.EOF only when one of the following occurs:
+//     * Exactly 0 bytes are read and EOF is hit.
+//     * Exactly 1 block of zeros is read and EOF is hit.
+//     * At least 2 blocks of zeros are read.
 func (tr *Reader) readHeader() *Header {
        header := tr.hdrBuff[:]
        copy(header, zeroBlock)
 
        if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
-               return nil
+               return nil // io.EOF is okay here
        }
 
        // Two blocks of zero bytes marks the end of the archive.
        if bytes.Equal(header, zeroBlock[0:blockSize]) {
                if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
-                       return nil
+                       return nil // io.EOF is okay here
                }
                if bytes.Equal(header, zeroBlock[0:blockSize]) {
                        tr.err = io.EOF
@@ -461,22 +588,19 @@ func (tr *Reader) readHeader() *Header {
        }
 
        // Unpack
+       var p parser
        hdr := new(Header)
        s := slicer(header)
 
-       hdr.Name = cString(s.next(100))
-       hdr.Mode = tr.octal(s.next(8))
-       hdr.Uid = int(tr.octal(s.next(8)))
-       hdr.Gid = int(tr.octal(s.next(8)))
-       hdr.Size = tr.octal(s.next(12))
-       if hdr.Size < 0 {
-               tr.err = ErrHeader
-               return nil
-       }
-       hdr.ModTime = time.Unix(tr.octal(s.next(12)), 0)
+       hdr.Name = p.parseString(s.next(100))
+       hdr.Mode = p.parseNumeric(s.next(8))
+       hdr.Uid = int(p.parseNumeric(s.next(8)))
+       hdr.Gid = int(p.parseNumeric(s.next(8)))
+       hdr.Size = p.parseNumeric(s.next(12))
+       hdr.ModTime = time.Unix(p.parseNumeric(s.next(12)), 0)
        s.next(8) // chksum
        hdr.Typeflag = s.next(1)[0]
-       hdr.Linkname = cString(s.next(100))
+       hdr.Linkname = p.parseString(s.next(100))
 
        // The remainder of the header depends on the value of magic.
        // The original (v7) version of tar had no explicit magic field,
@@ -496,70 +620,76 @@ func (tr *Reader) readHeader() *Header {
 
        switch format {
        case "posix", "gnu", "star":
-               hdr.Uname = cString(s.next(32))
-               hdr.Gname = cString(s.next(32))
+               hdr.Uname = p.parseString(s.next(32))
+               hdr.Gname = p.parseString(s.next(32))
                devmajor := s.next(8)
                devminor := s.next(8)
                if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock {
-                       hdr.Devmajor = tr.octal(devmajor)
-                       hdr.Devminor = tr.octal(devminor)
+                       hdr.Devmajor = p.parseNumeric(devmajor)
+                       hdr.Devminor = p.parseNumeric(devminor)
                }
                var prefix string
                switch format {
                case "posix", "gnu":
-                       prefix = cString(s.next(155))
+                       prefix = p.parseString(s.next(155))
                case "star":
-                       prefix = cString(s.next(131))
-                       hdr.AccessTime = time.Unix(tr.octal(s.next(12)), 0)
-                       hdr.ChangeTime = time.Unix(tr.octal(s.next(12)), 0)
+                       prefix = p.parseString(s.next(131))
+                       hdr.AccessTime = time.Unix(p.parseNumeric(s.next(12)), 0)
+                       hdr.ChangeTime = time.Unix(p.parseNumeric(s.next(12)), 0)
                }
                if len(prefix) > 0 {
                        hdr.Name = prefix + "/" + hdr.Name
                }
        }
 
-       if tr.err != nil {
-               tr.err = ErrHeader
+       if p.err != nil {
+               tr.err = p.err
                return nil
        }
 
-       // Maximum value of hdr.Size is 64 GB (12 octal digits),
-       // so there's no risk of int64 overflowing.
-       nb := int64(hdr.Size)
-       tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
+       nb := hdr.Size
+       if isHeaderOnlyType(hdr.Typeflag) {
+               nb = 0
+       }
+       if nb < 0 {
+               tr.err = ErrHeader
+               return nil
+       }
 
        // Set the current file reader.
+       tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
        tr.curr = &regFileReader{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])
+               hdr.Size = p.parseNumeric(header[483:495])
+               if p.err != nil {
+                       tr.err = p.err
+                       return nil
+               }
 
                // 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}
+               tr.curr, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size)
+               if tr.err != nil {
+                       return nil
+               }
        }
 
        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 {
+       var p parser
        isExtended := header[oldGNUSparseMainHeaderIsExtendedOffset] != 0
        spCap := oldGNUSparseMainHeaderNumEntries
        if isExtended {
@@ -570,10 +700,10 @@ func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
 
        // 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
+               offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize))
+               numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize))
+               if p.err != nil {
+                       tr.err = p.err
                        return nil
                }
                if offset == 0 && numBytes == 0 {
@@ -591,10 +721,10 @@ func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
                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
+                       offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize))
+                       numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize))
+                       if p.err != nil {
+                               tr.err = p.err
                                return nil
                        }
                        if offset == 0 && numBytes == 0 {
@@ -606,122 +736,111 @@ func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
        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.
+// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format
+// version 1.0. The format of the sparse map consists of a series of
+// newline-terminated numeric fields. The first field is the number of entries
+// and is always present. Following this are the entries, consisting of two
+// fields (offset, numBytes). This function must stop reading at the end
+// boundary of the block containing the last newline.
+//
+// Note that the GNU manual says that numeric values should be encoded in octal
+// format. However, the GNU tar utility itself outputs these values in decimal.
+// As such, this library treats values as being encoded in decimal.
 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
+       var cntNewline int64
+       var buf bytes.Buffer
+       var blk = make([]byte, blockSize)
+
+       // feedTokens copies data in numBlock chunks from r into buf until there are
+       // at least cnt newlines in buf. It will not read more blocks than needed.
+       var feedTokens = func(cnt int64) error {
+               for cntNewline < cnt {
+                       if _, err := io.ReadFull(r, blk); err != nil {
+                               if err == io.EOF {
+                                       err = io.ErrUnexpectedEOF
+                               }
+                               return 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
+                       buf.Write(blk)
+                       for _, c := range blk {
+                               if c == '\n' {
+                                       cntNewline++
+                               }
                        }
-                       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
                }
+               return nil
+       }
 
-               // Update sparseHeader to consume this number
-               sparseHeader = sparseHeader[nl+1:]
-               return n, nil
+       // nextToken gets the next token delimited by a newline. This assumes that
+       // at least one newline exists in the buffer.
+       var nextToken = func() string {
+               cntNewline--
+               tok, _ := buf.ReadString('\n')
+               return tok[:len(tok)-1] // Cut off newline
        }
 
-       // Read the first block
-       if _, err := io.ReadFull(r, sparseHeader); err != nil {
+       // Parse for the number of entries.
+       // Use integer overflow resistant math to check this.
+       if err := feedTokens(1); err != nil {
                return nil, err
        }
+       numEntries, err := strconv.ParseInt(nextToken(), 10, 0) // Intentionally parse as native int
+       if err != nil || numEntries < 0 || int(2*numEntries) < int(numEntries) {
+               return nil, ErrHeader
+       }
 
-       // The first line contains the number of entries
-       numEntries, err := readDecimal()
-       if err != nil {
+       // Parse for all member entries.
+       // numEntries is trusted after this since a potential attacker must have
+       // committed resources proportional to what this library used.
+       if err := feedTokens(2 * numEntries); 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()
+               offset, err := strconv.ParseInt(nextToken(), 10, 64)
                if err != nil {
-                       return nil, err
+                       return nil, ErrHeader
                }
-               // Read numBytes
-               numBytes, err := readDecimal()
+               numBytes, err := strconv.ParseInt(nextToken(), 10, 64)
                if err != nil {
-                       return nil, err
+                       return nil, ErrHeader
                }
-
                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 {
+// 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(extHdrs map[string]string) ([]sparseEntry, error) {
+       // Get number of entries.
+       // Use integer overflow resistant math to check this.
+       numEntriesStr := extHdrs[paxGNUSparseNumBlocks]
+       numEntries, err := strconv.ParseInt(numEntriesStr, 10, 0) // Intentionally parse as native int
+       if err != nil || numEntries < 0 || int(2*numEntries) < int(numEntries) {
                return nil, ErrHeader
        }
 
-       sparseMap := strings.Split(headers[paxGNUSparseMap], ",")
-
-       // There should be two numbers in sparseMap for each entry
+       // There should be two numbers in sparseMap for each entry.
+       sparseMap := strings.Split(extHdrs[paxGNUSparseMap], ",")
        if int64(len(sparseMap)) != 2*numEntries {
                return nil, ErrHeader
        }
 
-       // Loop through the entries in the sparse map
+       // Loop through the entries in the sparse map.
+       // numEntries is trusted now.
        sp := make([]sparseEntry, 0, numEntries)
        for i := int64(0); i < numEntries; i++ {
-               offset, err := strconv.ParseInt(sparseMap[2*i], 10, 0)
+               offset, err := strconv.ParseInt(sparseMap[2*i], 10, 64)
                if err != nil {
                        return nil, ErrHeader
                }
-               numBytes, err := strconv.ParseInt(sparseMap[2*i+1], 10, 0)
+               numBytes, err := strconv.ParseInt(sparseMap[2*i+1], 10, 64)
                if err != nil {
                        return nil, ErrHeader
                }
                sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
        }
-
        return sp, nil
 }
 
@@ -738,10 +857,18 @@ func (tr *Reader) numBytes() int64 {
 // 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.
+//
+// Calling Read on special types like TypeLink, TypeSymLink, TypeChar,
+// TypeBlock, TypeDir, and TypeFifo returns 0, io.EOF regardless of what
+// the Header.Size claims.
 func (tr *Reader) Read(b []byte) (n int, err error) {
+       if tr.err != nil {
+               return 0, tr.err
+       }
        if tr.curr == nil {
                return 0, io.EOF
        }
+
        n, err = tr.curr.Read(b)
        if err != nil && err != io.EOF {
                tr.err = err
@@ -771,9 +898,33 @@ 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
+// newSparseFileReader creates a new sparseFileReader, but validates all of the
+// sparse entries before doing so.
+func newSparseFileReader(rfr numBytesReader, sp []sparseEntry, total int64) (*sparseFileReader, error) {
+       if total < 0 {
+               return nil, ErrHeader // Total size cannot be negative
+       }
+
+       // Validate all sparse entries. These are the same checks as performed by
+       // the BSD tar utility.
+       for i, s := range sp {
+               switch {
+               case s.offset < 0 || s.numBytes < 0:
+                       return nil, ErrHeader // Negative values are never okay
+               case s.offset > math.MaxInt64-s.numBytes:
+                       return nil, ErrHeader // Integer overflow with large length
+               case s.offset+s.numBytes > total:
+                       return nil, ErrHeader // Region extends beyond the "real" size
+               case i > 0 && sp[i-1].offset+sp[i-1].numBytes > s.offset:
+                       return nil, ErrHeader // Regions can't overlap and must be in order
+               }
+       }
+       return &sparseFileReader{rfr: rfr, sp: sp, total: total}, nil
+}
+
+// readHole reads a sparse hole ending at endOffset.
+func (sfr *sparseFileReader) readHole(b []byte, endOffset int64) int {
+       n64 := endOffset - sfr.pos
        if n64 > int64(len(b)) {
                n64 = int64(len(b))
        }
@@ -787,49 +938,54 @@ func (sfr *sparseFileReader) readHole(b []byte, toOffset int64) int {
 
 // Read reads the sparse file data in expanded form.
 func (sfr *sparseFileReader) Read(b []byte) (n int, err error) {
+       // Skip past all empty fragments.
+       for len(sfr.sp) > 0 && sfr.sp[0].numBytes == 0 {
+               sfr.sp = sfr.sp[1:]
+       }
+
+       // If there are no more fragments, then it is possible that there
+       // is one last sparse hole.
        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
+               // This behavior matches the BSD tar utility.
+               // However, GNU tar stops returning data even if sfr.total is unmet.
+               if sfr.pos < sfr.total {
+                       return sfr.readHole(b, sfr.total), nil
                }
-               // Otherwise, we're at the end of the file
                return 0, io.EOF
        }
-       if sfr.tot < sfr.sp[0].offset {
-               return 0, io.ErrUnexpectedEOF
-       }
+
+       // In front of a data fragment, so read a hole.
        if sfr.pos < sfr.sp[0].offset {
-               // We're in a hole
-               n = sfr.readHole(b, sfr.sp[0].offset)
-               return
+               return sfr.readHole(b, sfr.sp[0].offset), nil
        }
 
-       // 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
+       // In a data fragment, so read from it.
+       // This math is overflow free since we verify that offset and numBytes can
+       // be safely added when creating the sparseFileReader.
+       endPos := sfr.sp[0].offset + sfr.sp[0].numBytes // End offset of fragment
+       bytesLeft := endPos - sfr.pos                   // Bytes left in fragment
        if int64(len(b)) > bytesLeft {
-               b = b[0:bytesLeft]
+               b = b[: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 {
+               if sfr.pos < endPos {
+                       err = io.ErrUnexpectedEOF // There was supposed to be more data
+               } else if sfr.pos < sfr.total {
+                       err = nil // There is still an implicit sparse hole at the end
+               }
        }
 
-       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
+       if sfr.pos == endPos {
+               sfr.sp = sfr.sp[1:] // We are done with this fragment, so pop it
        }
-       return
+       return n, err
 }
 
 // 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
+       return sfr.rfr.numBytes()
 }
index da01f265911806985c60c2be78a5fa67301fe875..7b148b5122bfacaf22b3048e79e39f694c4d5506 100644 (file)
@@ -10,6 +10,7 @@ import (
        "fmt"
        "io"
        "io/ioutil"
+       "math"
        "os"
        "reflect"
        "strings"
@@ -18,9 +19,10 @@ import (
 )
 
 type untarTest struct {
-       file    string
-       headers []*Header
-       cksums  []string
+       file    string    // Test input file
+       headers []*Header // Expected output headers
+       chksums []string  // MD5 checksum of files, leave as nil if not checked
+       err     error     // Expected error to occur
 }
 
 var gnuTarTest = &untarTest{
@@ -49,7 +51,7 @@ var gnuTarTest = &untarTest{
                        Gname:    "eng",
                },
        },
-       cksums: []string{
+       chksums: []string{
                "e38b27eaccb4391bdec553a7f3ae6b2f",
                "c65bd2e50a56a2138bf1716f2fd56fe9",
        },
@@ -129,7 +131,7 @@ var sparseTarTest = &untarTest{
                        Devminor: 0,
                },
        },
-       cksums: []string{
+       chksums: []string{
                "6f53234398c2449fe67c1812d993012f",
                "6f53234398c2449fe67c1812d993012f",
                "6f53234398c2449fe67c1812d993012f",
@@ -286,37 +288,119 @@ var untarTests = []*untarTest{
                        },
                },
        },
+       {
+               // Matches the behavior of GNU, BSD, and STAR tar utilities.
+               file: "testdata/gnu-multi-hdrs.tar",
+               headers: []*Header{
+                       {
+                               Name:     "GNU2/GNU2/long-path-name",
+                               Linkname: "GNU4/GNU4/long-linkpath-name",
+                               ModTime:  time.Unix(0, 0),
+                               Typeflag: '2',
+                       },
+               },
+       },
+       {
+               // Matches the behavior of GNU and BSD tar utilities.
+               file: "testdata/pax-multi-hdrs.tar",
+               headers: []*Header{
+                       {
+                               Name:     "bar",
+                               Linkname: "PAX4/PAX4/long-linkpath-name",
+                               ModTime:  time.Unix(0, 0),
+                               Typeflag: '2',
+                       },
+               },
+       },
+       {
+               file: "testdata/neg-size.tar",
+               err:  ErrHeader,
+       },
+       {
+               file: "testdata/issue10968.tar",
+               err:  ErrHeader,
+       },
+       {
+               file: "testdata/issue11169.tar",
+               err:  ErrHeader,
+       },
+       {
+               file: "testdata/issue12435.tar",
+               err:  ErrHeader,
+       },
 }
 
 func TestReader(t *testing.T) {
-testLoop:
-       for i, test := range untarTests {
-               f, err := os.Open(test.file)
+       for i, v := range untarTests {
+               f, err := os.Open(v.file)
                if err != nil {
-                       t.Errorf("test %d: Unexpected error: %v", i, err)
+                       t.Errorf("file %s, test %d: unexpected error: %v", v.file, i, err)
                        continue
                }
                defer f.Close()
-               tr := NewReader(f)
-               for j, header := range test.headers {
-                       hdr, err := tr.Next()
-                       if err != nil || hdr == nil {
-                               t.Errorf("test %d, entry %d: Didn't get entry: %v", i, j, err)
-                               f.Close()
-                               continue testLoop
+
+               // Capture all headers and checksums.
+               var (
+                       tr      = NewReader(f)
+                       hdrs    []*Header
+                       chksums []string
+                       rdbuf   = make([]byte, 8)
+               )
+               for {
+                       var hdr *Header
+                       hdr, err = tr.Next()
+                       if err != nil {
+                               if err == io.EOF {
+                                       err = nil // Expected error
+                               }
+                               break
                        }
-                       if !reflect.DeepEqual(*hdr, *header) {
-                               t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
-                                       i, j, *hdr, *header)
+                       hdrs = append(hdrs, hdr)
+
+                       if v.chksums == nil {
+                               continue
+                       }
+                       h := md5.New()
+                       _, err = io.CopyBuffer(h, tr, rdbuf) // Effectively an incremental read
+                       if err != nil {
+                               break
                        }
+                       chksums = append(chksums, fmt.Sprintf("%x", h.Sum(nil)))
                }
-               hdr, err := tr.Next()
-               if err == io.EOF {
-                       continue testLoop
+
+               for j, hdr := range hdrs {
+                       if j >= len(v.headers) {
+                               t.Errorf("file %s, test %d, entry %d: unexpected header:\ngot %+v",
+                                       v.file, i, j, *hdr)
+                               continue
+                       }
+                       if !reflect.DeepEqual(*hdr, *v.headers[j]) {
+                               t.Errorf("file %s, test %d, entry %d: incorrect header:\ngot  %+v\nwant %+v",
+                                       v.file, i, j, *hdr, *v.headers[j])
+                       }
+               }
+               if len(hdrs) != len(v.headers) {
+                       t.Errorf("file %s, test %d: got %d headers, want %d headers",
+                               v.file, i, len(hdrs), len(v.headers))
+               }
+
+               for j, sum := range chksums {
+                       if j >= len(v.chksums) {
+                               t.Errorf("file %s, test %d, entry %d: unexpected sum: got %s",
+                                       v.file, i, j, sum)
+                               continue
+                       }
+                       if sum != v.chksums[j] {
+                               t.Errorf("file %s, test %d, entry %d: incorrect checksum: got %s, want %s",
+                                       v.file, i, j, sum, v.chksums[j])
+                       }
                }
-               if hdr != nil || err != nil {
-                       t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, hdr, err)
+
+               if err != v.err {
+                       t.Errorf("file %s, test %d: unexpected error: got %v, want %v",
+                               v.file, i, err, v.err)
                }
+               f.Close()
        }
 }
 
@@ -356,89 +440,6 @@ func TestPartialRead(t *testing.T) {
        }
 }
 
-func TestIncrementalRead(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)
-
-       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 file contents in little chunks EOF,
-               // checksumming all the way
-               h := md5.New()
-               rdbuf := make([]uint8, 8)
-               for {
-                       nr, err := tr.Read(rdbuf)
-                       if err == io.EOF {
-                               break
-                       }
-                       if err != nil {
-                               t.Errorf("Read: unexpected error %v\n", err)
-                               break
-                       }
-                       h.Write(rdbuf[0:nr])
-               }
-               // 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)
-       }
-}
-
-func TestNonSeekable(t *testing.T) {
-       test := gnuTarTest
-       f, err := os.Open(test.file)
-       if err != nil {
-               t.Fatalf("Unexpected error: %v", err)
-       }
-       defer f.Close()
-
-       type readerOnly struct {
-               io.Reader
-       }
-       tr := NewReader(readerOnly{f})
-       nread := 0
-
-       for ; ; nread++ {
-               _, err := tr.Next()
-               if err == io.EOF {
-                       break
-               }
-               if err != nil {
-                       t.Fatalf("Unexpected error: %v", err)
-               }
-       }
-
-       if nread != len(test.headers) {
-               t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(test.headers), nread)
-       }
-}
-
 func TestParsePAXHeader(t *testing.T) {
        paxTests := [][3]string{
                {"a", "a=name", "10 a=name\n"}, // Test case involving multiple acceptable lengths
@@ -514,220 +515,312 @@ func TestMergePAX(t *testing.T) {
        }
 }
 
-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"),
+func TestSparseFileReader(t *testing.T) {
+       var vectors = []struct {
+               realSize   int64         // Real size of the output file
+               sparseMap  []sparseEntry // Input sparse map
+               sparseData string        // Input compact data
+               expected   string        // Expected output data
+               err        error         // Expected error outcome
+       }{{
+               realSize: 8,
                sparseMap: []sparseEntry{
                        {offset: 0, numBytes: 2},
                        {offset: 5, numBytes: 3},
                },
-               realSize: 8,
-               expected: []byte("ab\x00\x00\x00cde"),
-       },
-       {
-               sparseData: []byte("abcde"),
+               sparseData: "abcde",
+               expected:   "ab\x00\x00\x00cde",
+       }, {
+               realSize: 10,
                sparseMap: []sparseEntry{
                        {offset: 0, numBytes: 2},
                        {offset: 5, numBytes: 3},
                },
-               realSize: 10,
-               expected: []byte("ab\x00\x00\x00cde\x00\x00"),
-       },
-       {
-               sparseData: []byte("abcde"),
+               sparseData: "abcde",
+               expected:   "ab\x00\x00\x00cde\x00\x00",
+       }, {
+               realSize: 8,
                sparseMap: []sparseEntry{
                        {offset: 1, numBytes: 3},
                        {offset: 6, numBytes: 2},
                },
+               sparseData: "abcde",
+               expected:   "\x00abc\x00\x00de",
+       }, {
                realSize: 8,
-               expected: []byte("\x00abc\x00\x00de"),
-       },
-       {
-               sparseData: []byte("abcde"),
                sparseMap: []sparseEntry{
                        {offset: 1, numBytes: 3},
+                       {offset: 6, numBytes: 0},
+                       {offset: 6, numBytes: 0},
                        {offset: 6, numBytes: 2},
                },
+               sparseData: "abcde",
+               expected:   "\x00abc\x00\x00de",
+       }, {
                realSize: 10,
-               expected: []byte("\x00abc\x00\x00de\x00\x00"),
-       },
-       {
-               sparseData: []byte(""),
-               sparseMap:  nil,
+               sparseMap: []sparseEntry{
+                       {offset: 1, numBytes: 3},
+                       {offset: 6, numBytes: 2},
+               },
+               sparseData: "abcde",
+               expected:   "\x00abc\x00\x00de\x00\x00",
+       }, {
+               realSize: 10,
+               sparseMap: []sparseEntry{
+                       {offset: 1, numBytes: 3},
+                       {offset: 6, numBytes: 2},
+                       {offset: 8, numBytes: 0},
+                       {offset: 8, numBytes: 0},
+                       {offset: 8, numBytes: 0},
+                       {offset: 8, numBytes: 0},
+               },
+               sparseData: "abcde",
+               expected:   "\x00abc\x00\x00de\x00\x00",
+       }, {
                realSize:   2,
-               expected:   []byte("\x00\x00"),
-       },
-}
+               sparseMap:  []sparseEntry{},
+               sparseData: "",
+               expected:   "\x00\x00",
+       }, {
+               realSize:  -2,
+               sparseMap: []sparseEntry{},
+               err:       ErrHeader,
+       }, {
+               realSize: -10,
+               sparseMap: []sparseEntry{
+                       {offset: 1, numBytes: 3},
+                       {offset: 6, numBytes: 2},
+               },
+               sparseData: "abcde",
+               err:        ErrHeader,
+       }, {
+               realSize: 10,
+               sparseMap: []sparseEntry{
+                       {offset: 1, numBytes: 3},
+                       {offset: 6, numBytes: 5},
+               },
+               sparseData: "abcde",
+               err:        ErrHeader,
+       }, {
+               realSize: 35,
+               sparseMap: []sparseEntry{
+                       {offset: 1, numBytes: 3},
+                       {offset: 6, numBytes: 5},
+               },
+               sparseData: "abcde",
+               err:        io.ErrUnexpectedEOF,
+       }, {
+               realSize: 35,
+               sparseMap: []sparseEntry{
+                       {offset: 1, numBytes: 3},
+                       {offset: 6, numBytes: -5},
+               },
+               sparseData: "abcde",
+               err:        ErrHeader,
+       }, {
+               realSize: 35,
+               sparseMap: []sparseEntry{
+                       {offset: math.MaxInt64, numBytes: 3},
+                       {offset: 6, numBytes: -5},
+               },
+               sparseData: "abcde",
+               err:        ErrHeader,
+       }, {
+               realSize: 10,
+               sparseMap: []sparseEntry{
+                       {offset: 1, numBytes: 3},
+                       {offset: 2, numBytes: 2},
+               },
+               sparseData: "abcde",
+               err:        ErrHeader,
+       }}
 
-func TestSparseFileReader(t *testing.T) {
-       for i, test := range sparseFileReadTests {
-               r := bytes.NewReader(test.sparseData)
-               nb := int64(r.Len())
-               sfr := &sparseFileReader{
-                       rfr: &regFileReader{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)
+       for i, v := range vectors {
+               r := bytes.NewReader([]byte(v.sparseData))
+               rfr := &regFileReader{r: r, nb: int64(len(v.sparseData))}
+
+               var sfr *sparseFileReader
+               var err error
+               var buf []byte
+
+               sfr, err = newSparseFileReader(rfr, v.sparseMap, v.realSize)
+               if err != nil {
+                       goto fail
+               }
+               if sfr.numBytes() != int64(len(v.sparseData)) {
+                       t.Errorf("test %d, numBytes() before reading: got %d, want %d", i, sfr.numBytes(), len(v.sparseData))
+               }
+               buf, err = ioutil.ReadAll(sfr)
                if err != nil {
-                       t.Errorf("test %d: Unexpected error: %v", i, err)
+                       goto fail
                }
-               if e := test.expected; !bytes.Equal(buf, e) {
-                       t.Errorf("test %d: Contents = %v, want %v", i, buf, e)
+               if string(buf) != v.expected {
+                       t.Errorf("test %d, ReadAll(): got %q, want %q", i, string(buf), v.expected)
                }
                if sfr.numBytes() != 0 {
-                       t.Errorf("test %d: After draining the reader, numBytes() was nonzero", i)
+                       t.Errorf("test %d, numBytes() after reading: got %d, want %d", i, sfr.numBytes(), 0)
+               }
+
+       fail:
+               if err != v.err {
+                       t.Errorf("test %d, unexpected error: got %v, want %v", i, err, v.err)
                }
        }
 }
 
-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"
+func TestReadGNUSparseMap0x1(t *testing.T) {
+       const (
+               maxUint = ^uint(0)
+               maxInt  = int(maxUint >> 1)
+       )
+       var (
+               big1 = fmt.Sprintf("%d", int64(maxInt))
+               big2 = fmt.Sprintf("%d", (int64(maxInt)/2)+1)
+               big3 = fmt.Sprintf("%d", (int64(maxInt) / 3))
+       )
 
-       r := bytes.NewReader(sparseData)
-       nb := int64(r.Len())
-       sfr := &sparseFileReader{
-               rfr: &regFileReader{r: r, nb: nb},
-               sp:  sparseMap,
-               pos: 0,
-               tot: int64(len(expected)),
-       }
+       var vectors = []struct {
+               extHdrs   map[string]string // Input data
+               sparseMap []sparseEntry     // Expected sparse entries to be outputted
+               err       error             // Expected errors that may be raised
+       }{{
+               extHdrs: map[string]string{paxGNUSparseNumBlocks: "-4"},
+               err:     ErrHeader,
+       }, {
+               extHdrs: map[string]string{paxGNUSparseNumBlocks: "fee "},
+               err:     ErrHeader,
+       }, {
+               extHdrs: map[string]string{
+                       paxGNUSparseNumBlocks: big1,
+                       paxGNUSparseMap:       "0,5,10,5,20,5,30,5",
+               },
+               err: ErrHeader,
+       }, {
+               extHdrs: map[string]string{
+                       paxGNUSparseNumBlocks: big2,
+                       paxGNUSparseMap:       "0,5,10,5,20,5,30,5",
+               },
+               err: ErrHeader,
+       }, {
+               extHdrs: map[string]string{
+                       paxGNUSparseNumBlocks: big3,
+                       paxGNUSparseMap:       "0,5,10,5,20,5,30,5",
+               },
+               err: ErrHeader,
+       }, {
+               extHdrs: map[string]string{
+                       paxGNUSparseNumBlocks: "4",
+                       paxGNUSparseMap:       "0.5,5,10,5,20,5,30,5",
+               },
+               err: ErrHeader,
+       }, {
+               extHdrs: map[string]string{
+                       paxGNUSparseNumBlocks: "4",
+                       paxGNUSparseMap:       "0,5.5,10,5,20,5,30,5",
+               },
+               err: ErrHeader,
+       }, {
+               extHdrs: map[string]string{
+                       paxGNUSparseNumBlocks: "4",
+                       paxGNUSparseMap:       "0,fewafewa.5,fewafw,5,20,5,30,5",
+               },
+               err: ErrHeader,
+       }, {
+               extHdrs: map[string]string{
+                       paxGNUSparseNumBlocks: "4",
+                       paxGNUSparseMap:       "0,5,10,5,20,5,30,5",
+               },
+               sparseMap: []sparseEntry{{0, 5}, {10, 5}, {20, 5}, {30, 5}},
+       }}
 
-       // 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
+       for i, v := range vectors {
+               sp, err := readGNUSparseMap0x1(v.extHdrs)
+               if !reflect.DeepEqual(sp, v.sparseMap) && !(len(sp) == 0 && len(v.sparseMap) == 0) {
+                       t.Errorf("test %d, readGNUSparseMap0x1(...): got %v, want %v", i, sp, v.sparseMap)
                }
-               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)
-                       }
+               if err != v.err {
+                       t.Errorf("test %d, unexpected error: got %v, want %v", i, err, v.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},
+func TestReadGNUSparseMap1x0(t *testing.T) {
+       var sp = []sparseEntry{{1, 2}, {3, 4}}
+       for i := 0; i < 98; i++ {
+               sp = append(sp, sparseEntry{54321, 12345})
        }
 
-       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)
-       }
-}
+       var vectors = []struct {
+               input     string        // Input data
+               sparseMap []sparseEntry // Expected sparse entries to be outputted
+               cnt       int           // Expected number of bytes read
+               err       error         // Expected errors that may be raised
+       }{{
+               input: "",
+               cnt:   0,
+               err:   io.ErrUnexpectedEOF,
+       }, {
+               input: "ab",
+               cnt:   2,
+               err:   io.ErrUnexpectedEOF,
+       }, {
+               input: strings.Repeat("\x00", 512),
+               cnt:   512,
+               err:   io.ErrUnexpectedEOF,
+       }, {
+               input: strings.Repeat("\x00", 511) + "\n",
+               cnt:   512,
+               err:   ErrHeader,
+       }, {
+               input: strings.Repeat("\n", 512),
+               cnt:   512,
+               err:   ErrHeader,
+       }, {
+               input:     "0\n" + strings.Repeat("\x00", 510) + strings.Repeat("a", 512),
+               sparseMap: []sparseEntry{},
+               cnt:       512,
+       }, {
+               input:     strings.Repeat("0", 512) + "0\n" + strings.Repeat("\x00", 510),
+               sparseMap: []sparseEntry{},
+               cnt:       1024,
+       }, {
+               input:     strings.Repeat("0", 1024) + "1\n2\n3\n" + strings.Repeat("\x00", 506),
+               sparseMap: []sparseEntry{{2, 3}},
+               cnt:       1536,
+       }, {
+               input: strings.Repeat("0", 1024) + "1\n2\n\n" + strings.Repeat("\x00", 509),
+               cnt:   1536,
+               err:   ErrHeader,
+       }, {
+               input: strings.Repeat("0", 1024) + "1\n2\n" + strings.Repeat("\x00", 508),
+               cnt:   1536,
+               err:   io.ErrUnexpectedEOF,
+       }, {
+               input: "-1\n2\n\n" + strings.Repeat("\x00", 506),
+               cnt:   512,
+               err:   ErrHeader,
+       }, {
+               input: "1\nk\n2\n" + strings.Repeat("\x00", 506),
+               cnt:   512,
+               err:   ErrHeader,
+       }, {
+               input:     "100\n1\n2\n3\n4\n" + strings.Repeat("54321\n0000000000000012345\n", 98) + strings.Repeat("\x00", 512),
+               cnt:       2560,
+               sparseMap: sp,
+       }}
 
-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)
+       for i, v := range vectors {
+               r := strings.NewReader(v.input)
+               sp, err := readGNUSparseMap1x0(r)
+               if !reflect.DeepEqual(sp, v.sparseMap) && !(len(sp) == 0 && len(v.sparseMap) == 0) {
+                       t.Errorf("test %d, readGNUSparseMap1x0(...): got %v, want %v", i, sp, v.sparseMap)
+               }
+               if numBytes := len(v.input) - r.Len(); numBytes != v.cnt {
+                       t.Errorf("test %d, bytes read: got %v, want %v", i, numBytes, v.cnt)
+               }
+               if err != v.err {
+                       t.Errorf("test %d, unexpected error: got %v, want %v", i, err, v.err)
+               }
        }
 }
 
@@ -747,52 +840,286 @@ func TestUninitializedRead(t *testing.T) {
 
 }
 
-// Negative header size should not cause panic.
-// Issues 10959 and 10960.
-func TestNegativeHdrSize(t *testing.T) {
-       f, err := os.Open("testdata/neg-size.tar")
-       if err != nil {
-               t.Fatal(err)
+type reader struct{ io.Reader }
+type readSeeker struct{ io.ReadSeeker }
+type readBadSeeker struct{ io.ReadSeeker }
+
+func (rbs *readBadSeeker) Seek(int64, int) (int64, error) { return 0, fmt.Errorf("illegal seek") }
+
+// TestReadTruncation test the ending condition on various truncated files and
+// that truncated files are still detected even if the underlying io.Reader
+// satisfies io.Seeker.
+func TestReadTruncation(t *testing.T) {
+       var ss []string
+       for _, p := range []string{
+               "testdata/gnu.tar",
+               "testdata/ustar-file-reg.tar",
+               "testdata/pax-path-hdr.tar",
+               "testdata/sparse-formats.tar",
+       } {
+               buf, err := ioutil.ReadFile(p)
+               if err != nil {
+                       t.Fatalf("unexpected error: %v", err)
+               }
+               ss = append(ss, string(buf))
        }
-       defer f.Close()
-       r := NewReader(f)
-       _, err = r.Next()
-       if err != ErrHeader {
-               t.Error("want ErrHeader, got", err)
+
+       data1, data2, pax, sparse := ss[0], ss[1], ss[2], ss[3]
+       data2 += strings.Repeat("\x00", 10*512)
+       trash := strings.Repeat("garbage ", 64) // Exactly 512 bytes
+
+       var vectors = []struct {
+               input string // Input stream
+               cnt   int    // Expected number of headers read
+               err   error  // Expected error outcome
+       }{
+               {"", 0, io.EOF}, // Empty file is a "valid" tar file
+               {data1[:511], 0, io.ErrUnexpectedEOF},
+               {data1[:512], 1, io.ErrUnexpectedEOF},
+               {data1[:1024], 1, io.EOF},
+               {data1[:1536], 2, io.ErrUnexpectedEOF},
+               {data1[:2048], 2, io.EOF},
+               {data1, 2, io.EOF},
+               {data1[:2048] + data2[:1536], 3, io.EOF},
+               {data2[:511], 0, io.ErrUnexpectedEOF},
+               {data2[:512], 1, io.ErrUnexpectedEOF},
+               {data2[:1195], 1, io.ErrUnexpectedEOF},
+               {data2[:1196], 1, io.EOF}, // Exact end of data and start of padding
+               {data2[:1200], 1, io.EOF},
+               {data2[:1535], 1, io.EOF},
+               {data2[:1536], 1, io.EOF}, // Exact end of padding
+               {data2[:1536] + trash[:1], 1, io.ErrUnexpectedEOF},
+               {data2[:1536] + trash[:511], 1, io.ErrUnexpectedEOF},
+               {data2[:1536] + trash, 1, ErrHeader},
+               {data2[:2048], 1, io.EOF}, // Exactly 1 empty block
+               {data2[:2048] + trash[:1], 1, io.ErrUnexpectedEOF},
+               {data2[:2048] + trash[:511], 1, io.ErrUnexpectedEOF},
+               {data2[:2048] + trash, 1, ErrHeader},
+               {data2[:2560], 1, io.EOF}, // Exactly 2 empty blocks (normal end-of-stream)
+               {data2[:2560] + trash[:1], 1, io.EOF},
+               {data2[:2560] + trash[:511], 1, io.EOF},
+               {data2[:2560] + trash, 1, io.EOF},
+               {data2[:3072], 1, io.EOF},
+               {pax, 0, io.EOF}, // PAX header without data is a "valid" tar file
+               {pax + trash[:1], 0, io.ErrUnexpectedEOF},
+               {pax + trash[:511], 0, io.ErrUnexpectedEOF},
+               {sparse[:511], 0, io.ErrUnexpectedEOF},
+               // TODO(dsnet): This should pass, but currently fails.
+               // {sparse[:512], 0, io.ErrUnexpectedEOF},
+               {sparse[:3584], 1, io.EOF},
+               {sparse[:9200], 1, io.EOF}, // Terminate in padding of sparse header
+               {sparse[:9216], 1, io.EOF},
+               {sparse[:9728], 2, io.ErrUnexpectedEOF},
+               {sparse[:10240], 2, io.EOF},
+               {sparse[:11264], 2, io.ErrUnexpectedEOF},
+               {sparse, 5, io.EOF},
+               {sparse + trash, 5, io.EOF},
+       }
+
+       for i, v := range vectors {
+               for j := 0; j < 6; j++ {
+                       var tr *Reader
+                       var s1, s2 string
+
+                       switch j {
+                       case 0:
+                               tr = NewReader(&reader{strings.NewReader(v.input)})
+                               s1, s2 = "io.Reader", "auto"
+                       case 1:
+                               tr = NewReader(&reader{strings.NewReader(v.input)})
+                               s1, s2 = "io.Reader", "manual"
+                       case 2:
+                               tr = NewReader(&readSeeker{strings.NewReader(v.input)})
+                               s1, s2 = "io.ReadSeeker", "auto"
+                       case 3:
+                               tr = NewReader(&readSeeker{strings.NewReader(v.input)})
+                               s1, s2 = "io.ReadSeeker", "manual"
+                       case 4:
+                               tr = NewReader(&readBadSeeker{strings.NewReader(v.input)})
+                               s1, s2 = "ReadBadSeeker", "auto"
+                       case 5:
+                               tr = NewReader(&readBadSeeker{strings.NewReader(v.input)})
+                               s1, s2 = "ReadBadSeeker", "manual"
+                       }
+
+                       var cnt int
+                       var err error
+                       for {
+                               if _, err = tr.Next(); err != nil {
+                                       break
+                               }
+                               cnt++
+                               if s2 == "manual" {
+                                       if _, err = io.Copy(ioutil.Discard, tr); err != nil {
+                                               break
+                                       }
+                               }
+                       }
+                       if err != v.err {
+                               t.Errorf("test %d, NewReader(%s(...)) with %s discard: got %v, want %v",
+                                       i, s1, s2, err, v.err)
+                       }
+                       if cnt != v.cnt {
+                               t.Errorf("test %d, NewReader(%s(...)) with %s discard: got %d headers, want %d headers",
+                                       i, s1, s2, cnt, v.cnt)
+                       }
+               }
        }
-       io.Copy(ioutil.Discard, r)
 }
 
-// This used to hang in (*sparseFileReader).readHole due to missing
-// verification of sparse offsets against file size.
-func TestIssue10968(t *testing.T) {
-       f, err := os.Open("testdata/issue10968.tar")
+// TestReadHeaderOnly tests that Reader does not attempt to read special
+// header-only files.
+func TestReadHeaderOnly(t *testing.T) {
+       f, err := os.Open("testdata/hdr-only.tar")
        if err != nil {
-               t.Fatal(err)
+               t.Fatalf("unexpected error: %v", err)
        }
        defer f.Close()
-       r := NewReader(f)
-       _, err = r.Next()
-       if err != nil {
-               t.Fatal(err)
+
+       var hdrs []*Header
+       tr := NewReader(f)
+       for {
+               hdr, err := tr.Next()
+               if err == io.EOF {
+                       break
+               }
+               if err != nil {
+                       t.Errorf("Next(): got %v, want %v", err, nil)
+                       continue
+               }
+               hdrs = append(hdrs, hdr)
+
+               // If a special flag, we should read nothing.
+               cnt, _ := io.ReadFull(tr, []byte{0})
+               if cnt > 0 && hdr.Typeflag != TypeReg {
+                       t.Errorf("ReadFull(...): got %d bytes, want 0 bytes", cnt)
+               }
+       }
+
+       // File is crafted with 16 entries. The later 8 are identical to the first
+       // 8 except that the size is set.
+       if len(hdrs) != 16 {
+               t.Fatalf("len(hdrs): got %d, want %d", len(hdrs), 16)
        }
-       _, err = io.Copy(ioutil.Discard, r)
-       if err != io.ErrUnexpectedEOF {
-               t.Fatalf("expected %q, got %q", io.ErrUnexpectedEOF, err)
+       for i := 0; i < 8; i++ {
+               var hdr1, hdr2 = hdrs[i+0], hdrs[i+8]
+               hdr1.Size, hdr2.Size = 0, 0
+               if !reflect.DeepEqual(*hdr1, *hdr2) {
+                       t.Errorf("incorrect header:\ngot  %+v\nwant %+v", *hdr1, *hdr2)
+               }
        }
 }
 
-// Do not panic if there are errors in header blocks after the pax header.
-// Issue 11169
-func TestIssue11169(t *testing.T) {
-       f, err := os.Open("testdata/issue11169.tar")
-       if err != nil {
-               t.Fatal(err)
+func TestParsePAXRecord(t *testing.T) {
+       var medName = strings.Repeat("CD", 50)
+       var longName = strings.Repeat("AB", 100)
+
+       var vectors = []struct {
+               input     string
+               residual  string
+               outputKey string
+               outputVal string
+               ok        bool
+       }{
+               {"6 k=v\n\n", "\n", "k", "v", true},
+               {"19 path=/etc/hosts\n", "", "path", "/etc/hosts", true},
+               {"210 path=" + longName + "\nabc", "abc", "path", longName, true},
+               {"110 path=" + medName + "\n", "", "path", medName, true},
+               {"9 foo=ba\n", "", "foo", "ba", true},
+               {"11 foo=bar\n\x00", "\x00", "foo", "bar", true},
+               {"18 foo=b=\nar=\n==\x00\n", "", "foo", "b=\nar=\n==\x00", true},
+               {"27 foo=hello9 foo=ba\nworld\n", "", "foo", "hello9 foo=ba\nworld", true},
+               {"27 ☺☻☹=日a本b語ç\nmeow mix", "meow mix", "☺☻☹", "日a本b語ç", true},
+               {"17 \x00hello=\x00world\n", "", "\x00hello", "\x00world", true},
+               {"1 k=1\n", "1 k=1\n", "", "", false},
+               {"6 k~1\n", "6 k~1\n", "", "", false},
+               {"6_k=1\n", "6_k=1\n", "", "", false},
+               {"6 k=1 ", "6 k=1 ", "", "", false},
+               {"632 k=1\n", "632 k=1\n", "", "", false},
+               {"16 longkeyname=hahaha\n", "16 longkeyname=hahaha\n", "", "", false},
+               {"3 somelongkey=\n", "3 somelongkey=\n", "", "", false},
+               {"50 tooshort=\n", "50 tooshort=\n", "", "", false},
        }
-       defer f.Close()
-       r := NewReader(f)
-       _, err = r.Next()
-       if err == nil {
-               t.Fatal("Unexpected success")
+
+       for _, v := range vectors {
+               key, val, res, err := parsePAXRecord(v.input)
+               ok := (err == nil)
+               if v.ok != ok {
+                       if v.ok {
+                               t.Errorf("parsePAXRecord(%q): got parsing failure, want success", v.input)
+                       } else {
+                               t.Errorf("parsePAXRecord(%q): got parsing success, want failure", v.input)
+                       }
+               }
+               if ok && (key != v.outputKey || val != v.outputVal) {
+                       t.Errorf("parsePAXRecord(%q): got (%q: %q), want (%q: %q)",
+                               v.input, key, val, v.outputKey, v.outputVal)
+               }
+               if res != v.residual {
+                       t.Errorf("parsePAXRecord(%q): got residual %q, want residual %q",
+                               v.input, res, v.residual)
+               }
+       }
+}
+
+func TestParseNumeric(t *testing.T) {
+       var vectors = []struct {
+               input  string
+               output int64
+               ok     bool
+       }{
+               // Test base-256 (binary) encoded values.
+               {"", 0, true},
+               {"\x80", 0, true},
+               {"\x80\x00", 0, true},
+               {"\x80\x00\x00", 0, true},
+               {"\xbf", (1 << 6) - 1, true},
+               {"\xbf\xff", (1 << 14) - 1, true},
+               {"\xbf\xff\xff", (1 << 22) - 1, true},
+               {"\xff", -1, true},
+               {"\xff\xff", -1, true},
+               {"\xff\xff\xff", -1, true},
+               {"\xc0", -1 * (1 << 6), true},
+               {"\xc0\x00", -1 * (1 << 14), true},
+               {"\xc0\x00\x00", -1 * (1 << 22), true},
+               {"\x87\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
+               {"\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
+               {"\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
+               {"\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
+               {"\x80\x7f\xff\xff\xff\xff\xff\xff\xff", math.MaxInt64, true},
+               {"\x80\x80\x00\x00\x00\x00\x00\x00\x00", 0, false},
+               {"\xff\x80\x00\x00\x00\x00\x00\x00\x00", math.MinInt64, true},
+               {"\xff\x7f\xff\xff\xff\xff\xff\xff\xff", 0, false},
+               {"\xf5\xec\xd1\xc7\x7e\x5f\x26\x48\x81\x9f\x8f\x9b", 0, false},
+
+               // Test base-8 (octal) encoded values.
+               {"0000000\x00", 0, true},
+               {" \x0000000\x00", 0, true},
+               {" \x0000003\x00", 3, true},
+               {"00000000227\x00", 0227, true},
+               {"032033\x00 ", 032033, true},
+               {"320330\x00 ", 0320330, true},
+               {"0000660\x00 ", 0660, true},
+               {"\x00 0000660\x00 ", 0660, true},
+               {"0123456789abcdef", 0, false},
+               {"0123456789\x00abcdef", 0, false},
+               {"01234567\x0089abcdef", 342391, true},
+               {"0123\x7e\x5f\x264123", 0, false},
+       }
+
+       for _, v := range vectors {
+               var p parser
+               num := p.parseNumeric([]byte(v.input))
+               ok := (p.err == nil)
+               if v.ok != ok {
+                       if v.ok {
+                               t.Errorf("parseNumeric(%q): got parsing failure, want success", v.input)
+                       } else {
+                               t.Errorf("parseNumeric(%q): got parsing success, want failure", v.input)
+                       }
+               }
+               if ok && num != v.output {
+                       t.Errorf("parseNumeric(%q): got %d, want %d", v.input, num, v.output)
+               }
        }
 }
diff --git a/libgo/go/archive/tar/testdata/gnu-multi-hdrs.tar b/libgo/go/archive/tar/testdata/gnu-multi-hdrs.tar
new file mode 100644 (file)
index 0000000..8bcad55
Binary files /dev/null and b/libgo/go/archive/tar/testdata/gnu-multi-hdrs.tar differ
diff --git a/libgo/go/archive/tar/testdata/hdr-only.tar b/libgo/go/archive/tar/testdata/hdr-only.tar
new file mode 100644 (file)
index 0000000..f250340
Binary files /dev/null and b/libgo/go/archive/tar/testdata/hdr-only.tar differ
diff --git a/libgo/go/archive/tar/testdata/issue12435.tar b/libgo/go/archive/tar/testdata/issue12435.tar
new file mode 100644 (file)
index 0000000..3542dd8
Binary files /dev/null and b/libgo/go/archive/tar/testdata/issue12435.tar differ
index 5deea3d05c4da5a4ddda34ef7ad781088464e71b..21edf38cc3c3d98c834d07b6d31e8325898ec492 100644 (file)
Binary files a/libgo/go/archive/tar/testdata/neg-size.tar and b/libgo/go/archive/tar/testdata/neg-size.tar differ
diff --git a/libgo/go/archive/tar/testdata/pax-multi-hdrs.tar b/libgo/go/archive/tar/testdata/pax-multi-hdrs.tar
new file mode 100644 (file)
index 0000000..14bc759
Binary files /dev/null and b/libgo/go/archive/tar/testdata/pax-multi-hdrs.tar differ
diff --git a/libgo/go/archive/tar/testdata/pax-path-hdr.tar b/libgo/go/archive/tar/testdata/pax-path-hdr.tar
new file mode 100644 (file)
index 0000000..ab8fc32
Binary files /dev/null and b/libgo/go/archive/tar/testdata/pax-path-hdr.tar differ
diff --git a/libgo/go/archive/tar/testdata/ustar-file-reg.tar b/libgo/go/archive/tar/testdata/ustar-file-reg.tar
new file mode 100644 (file)
index 0000000..c84fa27
Binary files /dev/null and b/libgo/go/archive/tar/testdata/ustar-file-reg.tar differ
index 9dbc01a2ffbc4b223e0a28cfff3a40dc4817ca19..042638175cd84a75fa7b56b806f87c88612f45cc 100644 (file)
@@ -12,8 +12,8 @@ import (
        "errors"
        "fmt"
        "io"
-       "os"
        "path"
+       "sort"
        "strconv"
        "strings"
        "time"
@@ -23,7 +23,6 @@ var (
        ErrWriteTooLong    = errors.New("archive/tar: write too long")
        ErrFieldTooLong    = errors.New("archive/tar: header field too long")
        ErrWriteAfterClose = errors.New("archive/tar: write after close")
-       errNameTooLong     = errors.New("archive/tar: name too long")
        errInvalidHeader   = errors.New("archive/tar: header field too long or contains invalid values")
 )
 
@@ -43,6 +42,10 @@ type Writer struct {
        paxHdrBuff [blockSize]byte // buffer to use in writeHeader when writing a pax header
 }
 
+type formatter struct {
+       err error // Last error seen
+}
+
 // NewWriter creates a new Writer writing to w.
 func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }
 
@@ -69,17 +72,9 @@ func (tw *Writer) Flush() error {
 }
 
 // Write s into b, terminating it with a NUL if there is room.
-// If the value is too long for the field and allowPax is true add a paxheader record instead
-func (tw *Writer) cString(b []byte, s string, allowPax bool, paxKeyword string, paxHeaders map[string]string) {
-       needsPaxHeader := allowPax && len(s) > len(b) || !isASCII(s)
-       if needsPaxHeader {
-               paxHeaders[paxKeyword] = s
-               return
-       }
+func (f *formatter) formatString(b []byte, s string) {
        if len(s) > len(b) {
-               if tw.err == nil {
-                       tw.err = ErrFieldTooLong
-               }
+               f.err = ErrFieldTooLong
                return
        }
        ascii := toASCII(s)
@@ -90,40 +85,40 @@ func (tw *Writer) cString(b []byte, s string, allowPax bool, paxKeyword string,
 }
 
 // Encode x as an octal ASCII string and write it into b with leading zeros.
-func (tw *Writer) octal(b []byte, x int64) {
+func (f *formatter) formatOctal(b []byte, x int64) {
        s := strconv.FormatInt(x, 8)
        // leading zeros, but leave room for a NUL.
        for len(s)+1 < len(b) {
                s = "0" + s
        }
-       tw.cString(b, s, false, paxNone, nil)
+       f.formatString(b, s)
 }
 
-// Write x into b, either as octal or as binary (GNUtar/star extension).
-// If the value is too long for the field and writingPax is enabled both for the field and the add a paxheader record instead
-func (tw *Writer) numeric(b []byte, x int64, allowPax bool, paxKeyword string, paxHeaders map[string]string) {
-       // Try octal first.
-       s := strconv.FormatInt(x, 8)
-       if len(s) < len(b) {
-               tw.octal(b, x)
-               return
-       }
+// fitsInBase256 reports whether x can be encoded into n bytes using base-256
+// encoding. Unlike octal encoding, base-256 encoding does not require that the
+// string ends with a NUL character. Thus, all n bytes are available for output.
+//
+// If operating in binary mode, this assumes strict GNU binary mode; which means
+// that the first byte can only be either 0x80 or 0xff. Thus, the first byte is
+// equivalent to the sign bit in two's complement form.
+func fitsInBase256(n int, x int64) bool {
+       var binBits = uint(n-1) * 8
+       return n >= 9 || (x >= -1<<binBits && x < 1<<binBits)
+}
 
-       // If it is too long for octal, and pax is preferred, use a pax header
-       if allowPax && tw.preferPax {
-               tw.octal(b, 0)
-               s := strconv.FormatInt(x, 10)
-               paxHeaders[paxKeyword] = s
+// Write x into b, as binary (GNUtar/star extension).
+func (f *formatter) formatNumeric(b []byte, x int64) {
+       if fitsInBase256(len(b), x) {
+               for i := len(b) - 1; i >= 0; i-- {
+                       b[i] = byte(x)
+                       x >>= 8
+               }
+               b[0] |= 0x80 // Highest bit indicates binary format
                return
        }
 
-       // Too big: use binary (big-endian).
-       tw.usedBinary = true
-       for i := len(b) - 1; x > 0 && i >= 0; i-- {
-               b[i] = byte(x)
-               x >>= 8
-       }
-       b[0] |= 0x80 // highest bit indicates binary format
+       f.formatOctal(b, 0) // Last resort, just write zero
+       f.err = ErrFieldTooLong
 }
 
 var (
@@ -162,6 +157,7 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
        // subsecond time resolution, but for now let's just capture
        // too long fields or non ascii characters
 
+       var f formatter
        var header []byte
 
        // We need to select which scratch buffer to use carefully,
@@ -176,10 +172,40 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
        copy(header, zeroBlock)
        s := slicer(header)
 
+       // Wrappers around formatter that automatically sets paxHeaders if the
+       // argument extends beyond the capacity of the input byte slice.
+       var formatString = func(b []byte, s string, paxKeyword string) {
+               needsPaxHeader := paxKeyword != paxNone && len(s) > len(b) || !isASCII(s)
+               if needsPaxHeader {
+                       paxHeaders[paxKeyword] = s
+                       return
+               }
+               f.formatString(b, s)
+       }
+       var formatNumeric = func(b []byte, x int64, paxKeyword string) {
+               // Try octal first.
+               s := strconv.FormatInt(x, 8)
+               if len(s) < len(b) {
+                       f.formatOctal(b, x)
+                       return
+               }
+
+               // If it is too long for octal, and PAX is preferred, use a PAX header.
+               if paxKeyword != paxNone && tw.preferPax {
+                       f.formatOctal(b, 0)
+                       s := strconv.FormatInt(x, 10)
+                       paxHeaders[paxKeyword] = s
+                       return
+               }
+
+               tw.usedBinary = true
+               f.formatNumeric(b, x)
+       }
+
        // keep a reference to the filename to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
        pathHeaderBytes := s.next(fileNameSize)
 
-       tw.cString(pathHeaderBytes, hdr.Name, true, paxPath, paxHeaders)
+       formatString(pathHeaderBytes, hdr.Name, paxPath)
 
        // Handle out of range ModTime carefully.
        var modTime int64
@@ -187,25 +213,25 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
                modTime = hdr.ModTime.Unix()
        }
 
-       tw.octal(s.next(8), hdr.Mode)                                   // 100:108
-       tw.numeric(s.next(8), int64(hdr.Uid), true, paxUid, paxHeaders) // 108:116
-       tw.numeric(s.next(8), int64(hdr.Gid), true, paxGid, paxHeaders) // 116:124
-       tw.numeric(s.next(12), hdr.Size, true, paxSize, paxHeaders)     // 124:136
-       tw.numeric(s.next(12), modTime, false, paxNone, nil)            // 136:148 --- consider using pax for finer granularity
-       s.next(8)                                                       // chksum (148:156)
-       s.next(1)[0] = hdr.Typeflag                                     // 156:157
+       f.formatOctal(s.next(8), hdr.Mode)               // 100:108
+       formatNumeric(s.next(8), int64(hdr.Uid), paxUid) // 108:116
+       formatNumeric(s.next(8), int64(hdr.Gid), paxGid) // 116:124
+       formatNumeric(s.next(12), hdr.Size, paxSize)     // 124:136
+       formatNumeric(s.next(12), modTime, paxNone)      // 136:148 --- consider using pax for finer granularity
+       s.next(8)                                        // chksum (148:156)
+       s.next(1)[0] = hdr.Typeflag                      // 156:157
 
-       tw.cString(s.next(100), hdr.Linkname, true, paxLinkpath, paxHeaders)
+       formatString(s.next(100), hdr.Linkname, paxLinkpath)
 
-       copy(s.next(8), []byte("ustar\x0000"))                        // 257:265
-       tw.cString(s.next(32), hdr.Uname, true, paxUname, paxHeaders) // 265:297
-       tw.cString(s.next(32), hdr.Gname, true, paxGname, paxHeaders) // 297:329
-       tw.numeric(s.next(8), hdr.Devmajor, false, paxNone, nil)      // 329:337
-       tw.numeric(s.next(8), hdr.Devminor, false, paxNone, nil)      // 337:345
+       copy(s.next(8), []byte("ustar\x0000"))          // 257:265
+       formatString(s.next(32), hdr.Uname, paxUname)   // 265:297
+       formatString(s.next(32), hdr.Gname, paxGname)   // 297:329
+       formatNumeric(s.next(8), hdr.Devmajor, paxNone) // 329:337
+       formatNumeric(s.next(8), hdr.Devminor, paxNone) // 337:345
 
        // keep a reference to the prefix to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
        prefixHeaderBytes := s.next(155)
-       tw.cString(prefixHeaderBytes, "", false, paxNone, nil) // 345:500  prefix
+       formatString(prefixHeaderBytes, "", paxNone) // 345:500  prefix
 
        // Use the GNU magic instead of POSIX magic if we used any GNU extensions.
        if tw.usedBinary {
@@ -215,37 +241,26 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
        _, paxPathUsed := paxHeaders[paxPath]
        // try to use a ustar header when only the name is too long
        if !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed {
-               suffix := hdr.Name
-               prefix := ""
-               if len(hdr.Name) > fileNameSize && isASCII(hdr.Name) {
-                       var err error
-                       prefix, suffix, err = tw.splitUSTARLongName(hdr.Name)
-                       if err == nil {
-                               // ok we can use a ustar long name instead of pax, now correct the fields
-
-                               // remove the path field from the pax header. this will suppress the pax header
-                               delete(paxHeaders, paxPath)
-
-                               // update the path fields
-                               tw.cString(pathHeaderBytes, suffix, false, paxNone, nil)
-                               tw.cString(prefixHeaderBytes, prefix, false, paxNone, nil)
-
-                               // Use the ustar magic if we used ustar long names.
-                               if len(prefix) > 0 && !tw.usedBinary {
-                                       copy(header[257:265], []byte("ustar\x00"))
-                               }
-                       }
+               prefix, suffix, ok := splitUSTARPath(hdr.Name)
+               if ok {
+                       // Since we can encode in USTAR format, disable PAX header.
+                       delete(paxHeaders, paxPath)
+
+                       // Update the path fields
+                       formatString(pathHeaderBytes, suffix, paxNone)
+                       formatString(prefixHeaderBytes, prefix, paxNone)
                }
        }
 
        // The chksum field is terminated by a NUL and a space.
        // This is different from the other octal fields.
        chksum, _ := checksum(header)
-       tw.octal(header[148:155], chksum)
+       f.formatOctal(header[148:155], chksum) // Never fails
        header[155] = ' '
 
-       if tw.err != nil {
-               // problem with header; probably integer too big for a field.
+       // Check if there were any formatting errors.
+       if f.err != nil {
+               tw.err = f.err
                return tw.err
        }
 
@@ -270,28 +285,25 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
        return tw.err
 }
 
-// writeUSTARLongName splits a USTAR long name hdr.Name.
-// name must be < 256 characters. errNameTooLong is returned
-// if hdr.Name can't be split. The splitting heuristic
-// is compatible with gnu tar.
-func (tw *Writer) splitUSTARLongName(name string) (prefix, suffix string, err error) {
+// splitUSTARPath splits a path according to USTAR prefix and suffix rules.
+// If the path is not splittable, then it will return ("", "", false).
+func splitUSTARPath(name string) (prefix, suffix string, ok bool) {
        length := len(name)
-       if length > fileNamePrefixSize+1 {
+       if length <= fileNameSize || !isASCII(name) {
+               return "", "", false
+       } else if length > fileNamePrefixSize+1 {
                length = fileNamePrefixSize + 1
        } else if name[length-1] == '/' {
                length--
        }
+
        i := strings.LastIndex(name[:length], "/")
-       // nlen contains the resulting length in the name field.
-       // plen contains the resulting length in the prefix field.
-       nlen := len(name) - i - 1
-       plen := i
+       nlen := len(name) - i - 1 // nlen is length of suffix
+       plen := i                 // plen is length of prefix
        if i <= 0 || nlen > fileNameSize || nlen == 0 || plen > fileNamePrefixSize {
-               err = errNameTooLong
-               return
+               return "", "", false
        }
-       prefix, suffix = name[:i], name[i+1:]
-       return
+       return name[:i], name[i+1:], true
 }
 
 // writePaxHeader writes an extended pax header to the
@@ -304,11 +316,11 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) erro
        // succeed, and seems harmless enough.
        ext.ModTime = hdr.ModTime
        // The spec asks that we namespace our pseudo files
-       // with the current pid.
-       pid := os.Getpid()
+       // with the current pid.  However, this results in differing outputs
+       // for identical inputs.  As such, the constant 0 is now used instead.
+       // golang.org/issue/12358
        dir, file := path.Split(hdr.Name)
-       fullName := path.Join(dir,
-               fmt.Sprintf("PaxHeaders.%d", pid), file)
+       fullName := path.Join(dir, "PaxHeaders.0", file)
 
        ascii := toASCII(fullName)
        if len(ascii) > 100 {
@@ -318,8 +330,15 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) erro
        // Construct the body
        var buf bytes.Buffer
 
-       for k, v := range paxHeaders {
-               fmt.Fprint(&buf, paxHeader(k+"="+v))
+       // Keys are sorted before writing to body to allow deterministic output.
+       var keys []string
+       for k := range paxHeaders {
+               keys = append(keys, k)
+       }
+       sort.Strings(keys)
+
+       for _, k := range keys {
+               fmt.Fprint(&buf, formatPAXRecord(k, paxHeaders[k]))
        }
 
        ext.Size = int64(len(buf.Bytes()))
@@ -335,17 +354,18 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) erro
        return nil
 }
 
-// paxHeader formats a single pax record, prefixing it with the appropriate length
-func paxHeader(msg string) string {
-       const padding = 2 // Extra padding for space and newline
-       size := len(msg) + padding
+// formatPAXRecord formats a single PAX record, prefixing it with the
+// appropriate length.
+func formatPAXRecord(k, v string) string {
+       const padding = 3 // Extra padding for ' ', '=', and '\n'
+       size := len(k) + len(v) + padding
        size += len(strconv.Itoa(size))
-       record := fmt.Sprintf("%d %s\n", size, msg)
+       record := fmt.Sprintf("%d %s=%s\n", size, k, v)
+
+       // Final adjustment if adding size field increased the record size.
        if len(record) != size {
-               // Final adjustment if adding size increased
-               // the number of digits in size
                size = len(record)
-               record = fmt.Sprintf("%d %s\n", size, msg)
+               record = fmt.Sprintf("%d %s=%s\n", size, k, v)
        }
        return record
 }
index fe46a67ce38b1ce4c5943553b146ffb3b2e5e395..6e91d907ce96bdcb87247c15b144db96edf38288 100644 (file)
@@ -9,8 +9,10 @@ import (
        "fmt"
        "io"
        "io/ioutil"
+       "math"
        "os"
        "reflect"
+       "sort"
        "strings"
        "testing"
        "testing/iotest"
@@ -291,7 +293,7 @@ func TestPax(t *testing.T) {
                t.Fatal(err)
        }
        // Simple test to make sure PAX extensions are in effect
-       if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.")) {
+       if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
                t.Fatal("Expected at least one PAX header to be written.")
        }
        // Test that we can get a long name back out of the archive.
@@ -330,7 +332,7 @@ func TestPaxSymlink(t *testing.T) {
                t.Fatal(err)
        }
        // Simple test to make sure PAX extensions are in effect
-       if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.")) {
+       if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
                t.Fatal("Expected at least one PAX header to be written.")
        }
        // Test that we can get a long name back out of the archive.
@@ -380,7 +382,7 @@ func TestPaxNonAscii(t *testing.T) {
                t.Fatal(err)
        }
        // Simple test to make sure PAX extensions are in effect
-       if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.")) {
+       if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
                t.Fatal("Expected at least one PAX header to be written.")
        }
        // Test that we can get a long name back out of the archive.
@@ -439,21 +441,49 @@ func TestPaxXattrs(t *testing.T) {
        }
 }
 
-func TestPAXHeader(t *testing.T) {
-       medName := strings.Repeat("CD", 50)
-       longName := strings.Repeat("AB", 100)
-       paxTests := [][2]string{
-               {paxPath + "=/etc/hosts", "19 path=/etc/hosts\n"},
-               {"a=b", "6 a=b\n"},          // Single digit length
-               {"a=names", "11 a=names\n"}, // Test case involving carries
-               {paxPath + "=" + longName, fmt.Sprintf("210 path=%s\n", longName)},
-               {paxPath + "=" + medName, fmt.Sprintf("110 path=%s\n", medName)}}
-
-       for _, test := range paxTests {
-               key, expected := test[0], test[1]
-               if result := paxHeader(key); result != expected {
-                       t.Fatalf("paxHeader: got %s, expected %s", result, expected)
-               }
+func TestPaxHeadersSorted(t *testing.T) {
+       fileinfo, err := os.Stat("testdata/small.txt")
+       if err != nil {
+               t.Fatal(err)
+       }
+       hdr, err := FileInfoHeader(fileinfo, "")
+       if err != nil {
+               t.Fatalf("os.Stat: %v", err)
+       }
+       contents := strings.Repeat(" ", int(hdr.Size))
+
+       hdr.Xattrs = map[string]string{
+               "foo": "foo",
+               "bar": "bar",
+               "baz": "baz",
+               "qux": "qux",
+       }
+
+       var buf bytes.Buffer
+       writer := NewWriter(&buf)
+       if err := writer.WriteHeader(hdr); err != nil {
+               t.Fatal(err)
+       }
+       if _, err = writer.Write([]byte(contents)); err != nil {
+               t.Fatal(err)
+       }
+       if err := writer.Close(); err != nil {
+               t.Fatal(err)
+       }
+       // Simple test to make sure PAX extensions are in effect
+       if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
+               t.Fatal("Expected at least one PAX header to be written.")
+       }
+
+       // xattr bar should always appear before others
+       indices := []int{
+               bytes.Index(buf.Bytes(), []byte("bar=bar")),
+               bytes.Index(buf.Bytes(), []byte("baz=baz")),
+               bytes.Index(buf.Bytes(), []byte("foo=foo")),
+               bytes.Index(buf.Bytes(), []byte("qux=qux")),
+       }
+       if !sort.IntsAreSorted(indices) {
+               t.Fatal("PAX headers are not sorted")
        }
 }
 
@@ -544,3 +574,149 @@ func TestWriteAfterClose(t *testing.T) {
                t.Fatalf("Write: got %v; want ErrWriteAfterClose", err)
        }
 }
+
+func TestSplitUSTARPath(t *testing.T) {
+       var sr = strings.Repeat
+
+       var vectors = []struct {
+               input  string // Input path
+               prefix string // Expected output prefix
+               suffix string // Expected output suffix
+               ok     bool   // Split success?
+       }{
+               {"", "", "", false},
+               {"abc", "", "", false},
+               {"用戶名", "", "", false},
+               {sr("a", fileNameSize), "", "", false},
+               {sr("a", fileNameSize) + "/", "", "", false},
+               {sr("a", fileNameSize) + "/a", sr("a", fileNameSize), "a", true},
+               {sr("a", fileNamePrefixSize) + "/", "", "", false},
+               {sr("a", fileNamePrefixSize) + "/a", sr("a", fileNamePrefixSize), "a", true},
+               {sr("a", fileNameSize+1), "", "", false},
+               {sr("/", fileNameSize+1), sr("/", fileNameSize-1), "/", true},
+               {sr("a", fileNamePrefixSize) + "/" + sr("b", fileNameSize),
+                       sr("a", fileNamePrefixSize), sr("b", fileNameSize), true},
+               {sr("a", fileNamePrefixSize) + "//" + sr("b", fileNameSize), "", "", false},
+               {sr("a/", fileNameSize), sr("a/", 77) + "a", sr("a/", 22), true},
+       }
+
+       for _, v := range vectors {
+               prefix, suffix, ok := splitUSTARPath(v.input)
+               if prefix != v.prefix || suffix != v.suffix || ok != v.ok {
+                       t.Errorf("splitUSTARPath(%q):\ngot  (%q, %q, %v)\nwant (%q, %q, %v)",
+                               v.input, prefix, suffix, ok, v.prefix, v.suffix, v.ok)
+               }
+       }
+}
+
+func TestFormatPAXRecord(t *testing.T) {
+       var medName = strings.Repeat("CD", 50)
+       var longName = strings.Repeat("AB", 100)
+
+       var vectors = []struct {
+               inputKey string
+               inputVal string
+               output   string
+       }{
+               {"k", "v", "6 k=v\n"},
+               {"path", "/etc/hosts", "19 path=/etc/hosts\n"},
+               {"path", longName, "210 path=" + longName + "\n"},
+               {"path", medName, "110 path=" + medName + "\n"},
+               {"foo", "ba", "9 foo=ba\n"},
+               {"foo", "bar", "11 foo=bar\n"},
+               {"foo", "b=\nar=\n==\x00", "18 foo=b=\nar=\n==\x00\n"},
+               {"foo", "hello9 foo=ba\nworld", "27 foo=hello9 foo=ba\nworld\n"},
+               {"☺☻☹", "日a本b語ç", "27 ☺☻☹=日a本b語ç\n"},
+               {"\x00hello", "\x00world", "17 \x00hello=\x00world\n"},
+       }
+
+       for _, v := range vectors {
+               output := formatPAXRecord(v.inputKey, v.inputVal)
+               if output != v.output {
+                       t.Errorf("formatPAXRecord(%q, %q): got %q, want %q",
+                               v.inputKey, v.inputVal, output, v.output)
+               }
+       }
+}
+
+func TestFitsInBase256(t *testing.T) {
+       var vectors = []struct {
+               input int64
+               width int
+               ok    bool
+       }{
+               {+1, 8, true},
+               {0, 8, true},
+               {-1, 8, true},
+               {1 << 56, 8, false},
+               {(1 << 56) - 1, 8, true},
+               {-1 << 56, 8, true},
+               {(-1 << 56) - 1, 8, false},
+               {121654, 8, true},
+               {-9849849, 8, true},
+               {math.MaxInt64, 9, true},
+               {0, 9, true},
+               {math.MinInt64, 9, true},
+               {math.MaxInt64, 12, true},
+               {0, 12, true},
+               {math.MinInt64, 12, true},
+       }
+
+       for _, v := range vectors {
+               ok := fitsInBase256(v.width, v.input)
+               if ok != v.ok {
+                       t.Errorf("checkNumeric(%d, %d): got %v, want %v", v.input, v.width, ok, v.ok)
+               }
+       }
+}
+
+func TestFormatNumeric(t *testing.T) {
+       var vectors = []struct {
+               input  int64
+               output string
+               ok     bool
+       }{
+               // Test base-256 (binary) encoded values.
+               {-1, "\xff", true},
+               {-1, "\xff\xff", true},
+               {-1, "\xff\xff\xff", true},
+               {(1 << 0), "0", false},
+               {(1 << 8) - 1, "\x80\xff", true},
+               {(1 << 8), "0\x00", false},
+               {(1 << 16) - 1, "\x80\xff\xff", true},
+               {(1 << 16), "00\x00", false},
+               {-1 * (1 << 0), "\xff", true},
+               {-1*(1<<0) - 1, "0", false},
+               {-1 * (1 << 8), "\xff\x00", true},
+               {-1*(1<<8) - 1, "0\x00", false},
+               {-1 * (1 << 16), "\xff\x00\x00", true},
+               {-1*(1<<16) - 1, "00\x00", false},
+               {537795476381659745, "0000000\x00", false},
+               {537795476381659745, "\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", true},
+               {-615126028225187231, "0000000\x00", false},
+               {-615126028225187231, "\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", true},
+               {math.MaxInt64, "0000000\x00", false},
+               {math.MaxInt64, "\x80\x00\x00\x00\x7f\xff\xff\xff\xff\xff\xff\xff", true},
+               {math.MinInt64, "0000000\x00", false},
+               {math.MinInt64, "\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
+               {math.MaxInt64, "\x80\x7f\xff\xff\xff\xff\xff\xff\xff", true},
+               {math.MinInt64, "\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
+       }
+
+       for _, v := range vectors {
+               var f formatter
+               output := make([]byte, len(v.output))
+               f.formatNumeric(output, v.input)
+               ok := (f.err == nil)
+               if ok != v.ok {
+                       if v.ok {
+                               t.Errorf("formatNumeric(%d): got formatting failure, want success", v.input)
+                       } else {
+                               t.Errorf("formatNumeric(%d): got formatting success, want failure", v.input)
+                       }
+               }
+               if string(output) != v.output {
+                       t.Errorf("formatNumeric(%d): got %q, want %q", v.input, output, v.output)
+               }
+       }
+}
index 519748bac4006325228819074c7c984b9865063b..84a9d41888dd28664eca1195aa790bea53bde6fa 100644 (file)
@@ -22,9 +22,10 @@ var (
 )
 
 type Reader struct {
-       r       io.ReaderAt
-       File    []*File
-       Comment string
+       r             io.ReaderAt
+       File          []*File
+       Comment       string
+       decompressors map[uint16]Decompressor
 }
 
 type ReadCloser struct {
@@ -34,6 +35,7 @@ type ReadCloser struct {
 
 type File struct {
        FileHeader
+       zip          *Reader
        zipr         io.ReaderAt
        zipsize      int64
        headerOffset int64
@@ -95,7 +97,7 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
        // a bad one, and then only report a ErrFormat or UnexpectedEOF if
        // the file count modulo 65536 is incorrect.
        for {
-               f := &File{zipr: r, zipsize: size}
+               f := &File{zip: z, zipr: r, zipsize: size}
                err = readDirectoryHeader(f, buf)
                if err == ErrFormat || err == io.ErrUnexpectedEOF {
                        break
@@ -113,6 +115,24 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
        return nil
 }
 
+// RegisterDecompressor registers or overrides a custom decompressor for a
+// specific method ID. If a decompressor for a given method is not found,
+// Reader will default to looking up the decompressor at the package level.
+func (z *Reader) RegisterDecompressor(method uint16, dcomp Decompressor) {
+       if z.decompressors == nil {
+               z.decompressors = make(map[uint16]Decompressor)
+       }
+       z.decompressors[method] = dcomp
+}
+
+func (z *Reader) decompressor(method uint16) Decompressor {
+       dcomp := z.decompressors[method]
+       if dcomp == nil {
+               dcomp = decompressor(method)
+       }
+       return dcomp
+}
+
 // Close closes the Zip file, rendering it unusable for I/O.
 func (rc *ReadCloser) Close() error {
        return rc.f.Close()
@@ -140,7 +160,7 @@ func (f *File) Open() (rc io.ReadCloser, err error) {
        }
        size := int64(f.CompressedSize64)
        r := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset, size)
-       dcomp := decompressor(f.Method)
+       dcomp := f.zip.decompressor(f.Method)
        if dcomp == nil {
                err = ErrAlgorithm
                return
@@ -261,39 +281,59 @@ func readDirectoryHeader(f *File, r io.Reader) error {
        f.Extra = d[filenameLen : filenameLen+extraLen]
        f.Comment = string(d[filenameLen+extraLen:])
 
+       needUSize := f.UncompressedSize == ^uint32(0)
+       needCSize := f.CompressedSize == ^uint32(0)
+       needHeaderOffset := f.headerOffset == int64(^uint32(0))
+
        if len(f.Extra) > 0 {
+               // Best effort to find what we need.
+               // Other zip authors might not even follow the basic format,
+               // and we'll just ignore the Extra content in that case.
                b := readBuf(f.Extra)
                for len(b) >= 4 { // need at least tag and size
                        tag := b.uint16()
                        size := b.uint16()
                        if int(size) > len(b) {
-                               return ErrFormat
+                               break
                        }
                        if tag == zip64ExtraId {
-                               // update directory values from the zip64 extra block
+                               // update directory values from the zip64 extra block.
+                               // They should only be consulted if the sizes read earlier
+                               // are maxed out.
+                               // See golang.org/issue/13367.
                                eb := readBuf(b[:size])
-                               if len(eb) >= 8 {
+
+                               if needUSize {
+                                       needUSize = false
+                                       if len(eb) < 8 {
+                                               return ErrFormat
+                                       }
                                        f.UncompressedSize64 = eb.uint64()
                                }
-                               if len(eb) >= 8 {
+                               if needCSize {
+                                       needCSize = false
+                                       if len(eb) < 8 {
+                                               return ErrFormat
+                                       }
                                        f.CompressedSize64 = eb.uint64()
                                }
-                               if len(eb) >= 8 {
+                               if needHeaderOffset {
+                                       needHeaderOffset = false
+                                       if len(eb) < 8 {
+                                               return ErrFormat
+                                       }
                                        f.headerOffset = int64(eb.uint64())
                                }
+                               break
                        }
                        b = b[size:]
                }
-               // Should have consumed the whole header.
-               // But popular zip & JAR creation tools are broken and
-               // may pad extra zeros at the end, so accept those
-               // too. See golang.org/issue/8186.
-               for _, v := range b {
-                       if v != 0 {
-                               return ErrFormat
-                       }
-               }
        }
+
+       if needUSize || needCSize || needHeaderOffset {
+               return ErrFormat
+       }
+
        return nil
 }
 
@@ -376,14 +416,16 @@ func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error)
        }
        d.comment = string(b[:l])
 
-       p, err := findDirectory64End(r, directoryEndOffset)
-       if err == nil && p >= 0 {
-               err = readDirectory64End(r, p, d)
-       }
-       if err != nil {
-               return nil, err
+       // These values mean that the file can be a zip64 file
+       if d.directoryRecords == 0xffff || d.directorySize == 0xffff || d.directoryOffset == 0xffffffff {
+               p, err := findDirectory64End(r, directoryEndOffset)
+               if err == nil && p >= 0 {
+                       err = readDirectory64End(r, p, d)
+               }
+               if err != nil {
+                       return nil, err
+               }
        }
-
        // Make sure directoryOffset points to somewhere in our file.
        if o := int64(d.directoryOffset); o < 0 || o >= size {
                return nil, ErrFormat
@@ -407,8 +449,13 @@ func findDirectory64End(r io.ReaderAt, directoryEndOffset int64) (int64, error)
        if sig := b.uint32(); sig != directory64LocSignature {
                return -1, nil
        }
-       b = b[4:]       // skip number of the disk with the start of the zip64 end of central directory
-       p := b.uint64() // relative offset of the zip64 end of central directory record
+       if b.uint32() != 0 { // number of the disk with the start of the zip64 end of central directory
+               return -1, nil // the file is not a valid zip64-file
+       }
+       p := b.uint64()      // relative offset of the zip64 end of central directory record
+       if b.uint32() != 1 { // total number of disks
+               return -1, nil // the file is not a valid zip64-file
+       }
        return int64(p), nil
 }
 
index 547dd39048e21749faa6bebb159734bc4caf1599..8f7e8bf555d31cdb12f62cbc4aa2fb9f48d88ccc 100644 (file)
@@ -605,3 +605,40 @@ func TestIssue11146(t *testing.T) {
        }
        r.Close()
 }
+
+// Verify we do not treat non-zip64 archives as zip64
+func TestIssue12449(t *testing.T) {
+       data := []byte{
+               0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x00,
+               0x00, 0x00, 0x6b, 0xb4, 0xba, 0x46, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x03, 0x00, 0x18, 0x00, 0xca, 0x64,
+               0x55, 0x75, 0x78, 0x0b, 0x00, 0x50, 0x4b, 0x05,
+               0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
+               0x00, 0x49, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00,
+               0x00, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x0a,
+               0x50, 0x4b, 0x07, 0x08, 0x1d, 0x88, 0x77, 0xb0,
+               0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+               0x50, 0x4b, 0x01, 0x02, 0x14, 0x03, 0x14, 0x00,
+               0x08, 0x00, 0x00, 0x00, 0x6b, 0xb4, 0xba, 0x46,
+               0x1d, 0x88, 0x77, 0xb0, 0x07, 0x00, 0x00, 0x00,
+               0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x18, 0x00,
+               0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0xa0, 0x81, 0x00, 0x00, 0x00, 0x00, 0xca, 0x64,
+               0x55, 0x75, 0x78, 0x0b, 0x00, 0x50, 0x4b, 0x05,
+               0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
+               0x00, 0x49, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00,
+               0x00, 0x97, 0x2b, 0x49, 0x23, 0x05, 0xc5, 0x0b,
+               0xa7, 0xd1, 0x52, 0xa2, 0x9c, 0x50, 0x4b, 0x06,
+               0x07, 0xc8, 0x19, 0xc1, 0xaf, 0x94, 0x9c, 0x61,
+               0x44, 0xbe, 0x94, 0x19, 0x42, 0x58, 0x12, 0xc6,
+               0x5b, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00,
+               0x00, 0x01, 0x00, 0x01, 0x00, 0x69, 0x00, 0x00,
+               0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00,
+       }
+       // Read in the archive.
+       _, err := NewReader(bytes.NewReader([]byte(data)), int64(len(data)))
+       if err != nil {
+               t.Errorf("Error reading the archive: %v", err)
+       }
+}
index 4211ec7af7ba8ee56c5dcd194959230c5a000e07..8fccbf7ca09992e0188e5cf21e98bc173376a4c6 100644 (file)
@@ -12,15 +12,19 @@ import (
        "sync"
 )
 
-// A Compressor returns a compressing writer, writing to the
-// provided writer. On Close, any pending data should be flushed.
-type Compressor func(io.Writer) (io.WriteCloser, error)
-
-// Decompressor is a function that wraps a Reader with a decompressing Reader.
-// The decompressed ReadCloser is returned to callers who open files from
-// within the archive.  These callers are responsible for closing this reader
-// when they're finished reading.
-type Decompressor func(io.Reader) io.ReadCloser
+// A Compressor returns a new compressing writer, writing to w.
+// The WriteCloser's Close method must be used to flush pending data to w.
+// The Compressor itself must be safe to invoke from multiple goroutines
+// simultaneously, but each returned writer will be used only by
+// one goroutine at a time.
+type Compressor func(w io.Writer) (io.WriteCloser, error)
+
+// A Decompressor returns a new decompressing reader, reading from r.
+// The ReadCloser's Close method must be used to release associated resources.
+// The Decompressor itself must be safe to invoke from multiple goroutines
+// simultaneously, but each returned reader will be used only by
+// one goroutine at a time.
+type Decompressor func(r io.Reader) io.ReadCloser
 
 var flateWriterPool sync.Pool
 
@@ -75,14 +79,15 @@ var (
 )
 
 // RegisterDecompressor allows custom decompressors for a specified method ID.
-func RegisterDecompressor(method uint16, d Decompressor) {
+// The common methods Store and Deflate are built in.
+func RegisterDecompressor(method uint16, dcomp Decompressor) {
        mu.Lock()
        defer mu.Unlock()
 
        if _, ok := decompressors[method]; ok {
                panic("decompressor already registered")
        }
-       decompressors[method] = d
+       decompressors[method] = dcomp
 }
 
 // RegisterCompressor registers custom compressors for a specified method ID.
index 137d0495fd993439b32cc151a67be54017cb6270..5ee4f88f8036ba7d9dc1be55dd70ca52263b95e6 100644 (file)
@@ -235,7 +235,7 @@ func (h *FileHeader) SetMode(mode os.FileMode) {
 
 // isZip64 reports whether the file size exceeds the 32 bit limit
 func (fh *FileHeader) isZip64() bool {
-       return fh.CompressedSize64 > uint32max || fh.UncompressedSize64 > uint32max
+       return fh.CompressedSize64 >= uint32max || fh.UncompressedSize64 >= uint32max
 }
 
 func msdosModeToFileMode(m uint32) (mode os.FileMode) {
index 3be2b5fdb2f29417c0e9b384407fc56cad6bdc3e..5ce66e6be5eb1d2782cb0564c080a6ac72102f21 100644 (file)
@@ -14,14 +14,14 @@ import (
 )
 
 // TODO(adg): support zip file comments
-// TODO(adg): support specifying deflate level
 
 // Writer implements a zip file writer.
 type Writer struct {
-       cw     *countWriter
-       dir    []*header
-       last   *fileWriter
-       closed bool
+       cw          *countWriter
+       dir         []*header
+       last        *fileWriter
+       closed      bool
+       compressors map[uint16]Compressor
 }
 
 type header struct {
@@ -78,7 +78,7 @@ func (w *Writer) Close() error {
                b.uint16(h.ModifiedTime)
                b.uint16(h.ModifiedDate)
                b.uint32(h.CRC32)
-               if h.isZip64() || h.offset > uint32max {
+               if h.isZip64() || h.offset >= uint32max {
                        // the file needs a zip64 header. store maxint in both
                        // 32 bit size fields (and offset later) to signal that the
                        // zip64 extra header should be used.
@@ -220,7 +220,7 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
                compCount: &countWriter{w: w.cw},
                crc32:     crc32.NewIEEE(),
        }
-       comp := compressor(fh.Method)
+       comp := w.compressor(fh.Method)
        if comp == nil {
                return nil, ErrAlgorithm
        }
@@ -270,6 +270,24 @@ func writeHeader(w io.Writer, h *FileHeader) error {
        return err
 }
 
+// RegisterCompressor registers or overrides a custom compressor for a specific
+// method ID. If a compressor for a given method is not found, Writer will
+// default to looking up the compressor at the package level.
+func (w *Writer) RegisterCompressor(method uint16, comp Compressor) {
+       if w.compressors == nil {
+               w.compressors = make(map[uint16]Compressor)
+       }
+       w.compressors[method] = comp
+}
+
+func (w *Writer) compressor(method uint16) Compressor {
+       comp := w.compressors[method]
+       if comp == nil {
+               comp = compressor(method)
+       }
+       return comp
+}
+
 type fileWriter struct {
        *header
        zipw      io.Writer
index f00ff47d37ecb29d0fa89cb303a6a17f01cdb812..f785abf50aac88faa34d63b90395e9794115a247 100644 (file)
@@ -10,6 +10,7 @@ import (
        "bytes"
        "fmt"
        "hash"
+       "internal/testenv"
        "io"
        "io/ioutil"
        "sort"
@@ -19,6 +20,9 @@ import (
 )
 
 func TestOver65kFiles(t *testing.T) {
+       if testing.Short() && testenv.Builder() == "" {
+               t.Skip("skipping in short mode")
+       }
        buf := new(bytes.Buffer)
        w := NewWriter(buf)
        const nFiles = (1 << 16) + 42
@@ -233,10 +237,24 @@ func TestZip64(t *testing.T) {
        testZip64DirectoryRecordLength(buf, t)
 }
 
+func TestZip64EdgeCase(t *testing.T) {
+       if testing.Short() {
+               t.Skip("slow test; skipping")
+       }
+       // Test a zip file with uncompressed size 0xFFFFFFFF.
+       // That's the magic marker for a 64-bit file, so even though
+       // it fits in a 32-bit field we must use the 64-bit field.
+       // Go 1.5 and earlier got this wrong,
+       // writing an invalid zip file.
+       const size = 1<<32 - 1 - int64(len("END\n")) // before the "END\n" part
+       buf := testZip64(t, size)
+       testZip64DirectoryRecordLength(buf, t)
+}
+
 func testZip64(t testing.TB, size int64) *rleBuffer {
        const chunkSize = 1024
        chunks := int(size / chunkSize)
-       // write 2^32 bytes plus "END\n" to a zip file
+       // write size bytes plus "END\n" to a zip file
        buf := new(rleBuffer)
        w := NewWriter(buf)
        f, err := w.CreateHeader(&FileHeader{
@@ -257,6 +275,12 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
                        t.Fatal("write chunk:", err)
                }
        }
+       if frag := int(size % chunkSize); frag > 0 {
+               _, err := f.Write(chunk[:frag])
+               if err != nil {
+                       t.Fatal("write chunk:", err)
+               }
+       }
        end := []byte("END\n")
        _, err = f.Write(end)
        if err != nil {
@@ -283,6 +307,12 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
                        t.Fatal("read:", err)
                }
        }
+       if frag := int(size % chunkSize); frag > 0 {
+               _, err := io.ReadFull(rc, chunk[:frag])
+               if err != nil {
+                       t.Fatal("read:", err)
+               }
+       }
        gotEnd, err := ioutil.ReadAll(rc)
        if err != nil {
                t.Fatal("read end:", err)
@@ -294,14 +324,14 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
        if err != nil {
                t.Fatal("closing:", err)
        }
-       if size == 1<<32 {
+       if size+int64(len("END\n")) >= 1<<32-1 {
                if got, want := f0.UncompressedSize, uint32(uint32max); got != want {
-                       t.Errorf("UncompressedSize %d, want %d", got, want)
+                       t.Errorf("UncompressedSize %#x, want %#x", got, want)
                }
        }
 
        if got, want := f0.UncompressedSize64, uint64(size)+uint64(len(end)); got != want {
-               t.Errorf("UncompressedSize64 %d, want %d", got, want)
+               t.Errorf("UncompressedSize64 %#x, want %#x", got, want)
        }
 
        return buf
@@ -373,9 +403,14 @@ func testValidHeader(h *FileHeader, t *testing.T) {
        }
 
        b := buf.Bytes()
-       if _, err = NewReader(bytes.NewReader(b), int64(len(b))); err != nil {
+       zf, err := NewReader(bytes.NewReader(b), int64(len(b)))
+       if err != nil {
                t.Fatalf("got %v, expected nil", err)
        }
+       zh := zf.File[0].FileHeader
+       if zh.Name != h.Name || zh.Method != h.Method || zh.UncompressedSize64 != uint64(len("hi")) {
+               t.Fatalf("got %q/%d/%d expected %q/%d/%d", zh.Name, zh.Method, zh.UncompressedSize64, h.Name, h.Method, len("hi"))
+       }
 }
 
 // Issue 4302.
@@ -388,20 +423,29 @@ func TestHeaderInvalidTagAndSize(t *testing.T) {
        h := FileHeader{
                Name:   filename,
                Method: Deflate,
-               Extra:  []byte(ts.Format(time.RFC3339Nano)), // missing tag and len
+               Extra:  []byte(ts.Format(time.RFC3339Nano)), // missing tag and len, but Extra is best-effort parsing
        }
        h.SetModTime(ts)
 
-       testInvalidHeader(&h, t)
+       testValidHeader(&h, t)
 }
 
 func TestHeaderTooShort(t *testing.T) {
        h := FileHeader{
                Name:   "foo.txt",
                Method: Deflate,
-               Extra:  []byte{zip64ExtraId}, // missing size
+               Extra:  []byte{zip64ExtraId}, // missing size and second half of tag, but Extra is best-effort parsing
        }
-       testInvalidHeader(&h, t)
+       testValidHeader(&h, t)
+}
+
+func TestHeaderIgnoredSize(t *testing.T) {
+       h := FileHeader{
+               Name:   "foo.txt",
+               Method: Deflate,
+               Extra:  []byte{zip64ExtraId & 0xFF, zip64ExtraId >> 8, 24, 0, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}, // bad size but shouldn't be consulted
+       }
+       testValidHeader(&h, t)
 }
 
 // Issue 4393. It is valid to have an extra data header
index 3bbb933df3569886ade4c370144d08ae63101c86..6a70f7034d043142c30f27a19d56bb28d6113b2a 100644 (file)
@@ -179,7 +179,7 @@ func (b *Reader) Discard(n int) (discarded int, err error) {
 
 // Read reads data into p.
 // It returns the number of bytes read into p.
-// It calls Read at most once on the underlying Reader,
+// The bytes are taken from at most one Read on the underlying Reader,
 // hence n may be less than len(p).
 // At EOF, the count will be zero and err will be io.EOF.
 func (b *Reader) Read(p []byte) (n int, err error) {
index 3da914142194895ea37e660c621d3835fb251a86..4666e6d985561c565ba95c016cda2149cc00373a 100644 (file)
@@ -80,3 +80,32 @@ func ExampleScanner_custom() {
        // 5678
        // Invalid input: strconv.ParseInt: parsing "1234567901234567890": value out of range
 }
+
+// Use a Scanner with a custom split function to parse a comma-separated
+// list with an empty final value.
+func ExampleScanner_emptyFinalToken() {
+       // Comma-separated list; last entry is empty.
+       const input = "1,2,3,4,"
+       scanner := bufio.NewScanner(strings.NewReader(input))
+       // Define a split function that separates on commas.
+       onComma := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
+               for i := 0; i < len(data); i++ {
+                       if data[i] == ',' {
+                               return i + 1, data[:i], nil
+                       }
+               }
+               // There is one final token to be delivered, which may be the empty string.
+               // Returning bufio.ErrFinalToken here tells Scan there are no more tokens after this
+               // but does not trigger an error to be returned from Scan itself.
+               return 0, data, bufio.ErrFinalToken
+       }
+       scanner.Split(onComma)
+       // Scan.
+       for scanner.Scan() {
+               fmt.Printf("%q ", scanner.Text())
+       }
+       if err := scanner.Err(); err != nil {
+               fmt.Fprintln(os.Stderr, "reading input:", err)
+       }
+       // Output: "1" "2" "3" "4" ""
+}
index 7a349fa8fab7e5d0a7dc37c12af4cb8279b2a612..27a0f0045955e301ce698723e6a89c93c135c9e9 100644 (file)
@@ -37,6 +37,8 @@ type Scanner struct {
        end          int       // End of data in buf.
        err          error     // Sticky error.
        empties      int       // Count of successive empty tokens.
+       scanCalled   bool      // Scan has been called; buffer is in use.
+       done         bool      // Scan has finished.
 }
 
 // SplitFunc is the signature of the split function used to tokenize the
@@ -65,10 +67,13 @@ var (
 )
 
 const (
-       // MaxScanTokenSize is the maximum size used to buffer a token.
+       // MaxScanTokenSize is the maximum size used to buffer a token
+       // unless the user provides an explicit buffer with Scan.Buffer.
        // The actual maximum token size may be smaller as the buffer
        // may need to include, for instance, a newline.
        MaxScanTokenSize = 64 * 1024
+
+       startBufSize = 4096 // Size of initial allocation for buffer.
 )
 
 // NewScanner returns a new Scanner to read from r.
@@ -78,7 +83,6 @@ func NewScanner(r io.Reader) *Scanner {
                r:            r,
                split:        ScanLines,
                maxTokenSize: MaxScanTokenSize,
-               buf:          make([]byte, 4096), // Plausible starting size; needn't be large.
        }
 }
 
@@ -103,6 +107,16 @@ func (s *Scanner) Text() string {
        return string(s.token)
 }
 
+// ErrFinalToken is a special sentinel error value. It is intended to be
+// returned by a Split function to indicate that the token being delivered
+// with the error is the last token and scanning should stop after this one.
+// After ErrFinalToken is received by Scan, scanning stops with no error.
+// The value is useful to stop processing early or when it is necessary to
+// deliver a final empty token. One could achieve the same behavior
+// with a custom error value but providing one here is tidier.
+// See the emptyFinalToken example for a use of this value.
+var ErrFinalToken = errors.New("final token")
+
 // Scan advances the Scanner to the next token, which will then be
 // available through the Bytes or Text method. It returns false when the
 // scan stops, either by reaching the end of the input or an error.
@@ -112,6 +126,10 @@ func (s *Scanner) Text() string {
 // Scan panics if the split function returns 100 empty tokens without
 // advancing the input. This is a common error mode for scanners.
 func (s *Scanner) Scan() bool {
+       if s.done {
+               return false
+       }
+       s.scanCalled = true
        // Loop until we have a token.
        for {
                // See if we can get a token with what we already have.
@@ -120,6 +138,11 @@ func (s *Scanner) Scan() bool {
                if s.end > s.start || s.err != nil {
                        advance, token, err := s.split(s.buf[s.start:s.end], s.err != nil)
                        if err != nil {
+                               if err == ErrFinalToken {
+                                       s.token = token
+                                       s.done = true
+                                       return true
+                               }
                                s.setErr(err)
                                return false
                        }
@@ -158,11 +181,16 @@ func (s *Scanner) Scan() bool {
                }
                // Is the buffer full? If so, resize.
                if s.end == len(s.buf) {
-                       if len(s.buf) >= s.maxTokenSize {
+                       // Guarantee no overflow in the multiplication below.
+                       const maxInt = int(^uint(0) >> 1)
+                       if len(s.buf) >= s.maxTokenSize || len(s.buf) > maxInt/2 {
                                s.setErr(ErrTooLong)
                                return false
                        }
                        newSize := len(s.buf) * 2
+                       if newSize == 0 {
+                               newSize = startBufSize
+                       }
                        if newSize > s.maxTokenSize {
                                newSize = s.maxTokenSize
                        }
@@ -217,9 +245,31 @@ func (s *Scanner) setErr(err error) {
        }
 }
 
-// Split sets the split function for the Scanner. If called, it must be
-// called before Scan. The default split function is ScanLines.
+// Buffer sets the initial buffer to use when scanning and the maximum
+// size of buffer that may be allocated during scanning. The maximum
+// token size is the larger of max and cap(buf). If max <= cap(buf),
+// Scan will use this buffer only and do no allocation.
+//
+// By default, Scan uses an internal buffer and sets the
+// maximum token size to MaxScanTokenSize.
+//
+// Buffer panics if it is called after scanning has started.
+func (s *Scanner) Buffer(buf []byte, max int) {
+       if s.scanCalled {
+               panic("Buffer called after Scan")
+       }
+       s.buf = buf[0:cap(buf)]
+       s.maxTokenSize = max
+}
+
+// Split sets the split function for the Scanner.
+// The default split function is ScanLines.
+//
+// Split panics if it is called after scanning has started.
 func (s *Scanner) Split(split SplitFunc) {
+       if s.scanCalled {
+               panic("Split called after Scan")
+       }
        s.split = split
 }
 
index eea87cbf7b39de26059bb7f1dd673b37820d868e..07b1a56dc0a4654a294b5085c5a6a6aad15e5831 100644 (file)
@@ -429,33 +429,37 @@ func commaSplit(data []byte, atEOF bool) (advance int, token []byte, err error)
                        return i + 1, data[:i], nil
                }
        }
-       if !atEOF {
-               return 0, nil, nil
-       }
-       return 0, data, nil
+       return 0, data, ErrFinalToken
 }
 
-func TestEmptyTokens(t *testing.T) {
-       s := NewScanner(strings.NewReader("1,2,3,"))
-       values := []string{"1", "2", "3", ""}
+func testEmptyTokens(t *testing.T, text string, values []string) {
+       s := NewScanner(strings.NewReader(text))
        s.Split(commaSplit)
        var i int
-       for i = 0; i < len(values); i++ {
-               if !s.Scan() {
-                       break
+       for i = 0; s.Scan(); i++ {
+               if i >= len(values) {
+                       t.Fatalf("got %d fields, expected %d", i+1, len(values))
                }
                if s.Text() != values[i] {
                        t.Errorf("%d: expected %q got %q", i, values[i], s.Text())
                }
        }
        if i != len(values) {
-               t.Errorf("got %d fields, expected %d", i, len(values))
+               t.Fatalf("got %d fields, expected %d", i, len(values))
        }
        if err := s.Err(); err != nil {
                t.Fatal(err)
        }
 }
 
+func TestEmptyTokens(t *testing.T) {
+       testEmptyTokens(t, "1,2,3,", []string{"1", "2", "3", ""})
+}
+
+func TestWithNoEmptyTokens(t *testing.T) {
+       testEmptyTokens(t, "1,2,3", []string{"1", "2", "3"})
+}
+
 func loopAtEOFSplit(data []byte, atEOF bool) (advance int, token []byte, err error) {
        if len(data) > 0 {
                return 1, data[:1], nil
@@ -522,3 +526,19 @@ func TestEmptyLinesOK(t *testing.T) {
                t.Fatalf("stopped with %d left to process", c)
        }
 }
+
+// Make sure we can read a huge token if a big enough buffer is provided.
+func TestHugeBuffer(t *testing.T) {
+       text := strings.Repeat("x", 2*MaxScanTokenSize)
+       s := NewScanner(strings.NewReader(text + "\n"))
+       s.Buffer(make([]byte, 100), 3*MaxScanTokenSize)
+       for s.Scan() {
+               token := s.Text()
+               if token != text {
+                       t.Errorf("scan got incorrect token of length %d", len(token))
+               }
+       }
+       if s.Err() != nil {
+               t.Fatal("after scan:", s.Err())
+       }
+}
index 4db93867d9aa890faed03430b8d9116714e4c9ea..ddaba3bff351e0977ea617372960eb39d9641001 100644 (file)
@@ -36,10 +36,11 @@ const (
 // ErrTooLarge is passed to panic if memory cannot be allocated to store data in a buffer.
 var ErrTooLarge = errors.New("bytes.Buffer: too large")
 
-// Bytes returns a slice of the contents of the unread portion of the buffer;
-// len(b.Bytes()) == b.Len().  If the caller changes the contents of the
-// returned slice, the contents of the buffer will change provided there
-// are no intervening method calls on the Buffer.
+// Bytes returns a slice of length b.Len() holding the unread portion of the buffer.
+// The slice is valid for use only until the next buffer modification (that is,
+// only until the next call to a method like Read, Write, Reset, or Truncate).
+// The slice aliases the buffer content at least until the next buffer modification,
+// so immediate changes to the slice will affect the result of future reads.
 func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }
 
 // String returns the contents of the unread portion of the buffer
@@ -60,7 +61,8 @@ func (b *Buffer) Len() int { return len(b.buf) - b.off }
 // total space allocated for the buffer's data.
 func (b *Buffer) Cap() int { return cap(b.buf) }
 
-// Truncate discards all but the first n unread bytes from the buffer.
+// Truncate discards all but the first n unread bytes from the buffer
+// but continues to use the same allocated storage.
 // It panics if n is negative or greater than the length of the buffer.
 func (b *Buffer) Truncate(n int) {
        b.lastRead = opInvalid
@@ -74,8 +76,9 @@ func (b *Buffer) Truncate(n int) {
        b.buf = b.buf[0 : b.off+n]
 }
 
-// Reset resets the buffer so it has no content.
-// b.Reset() is the same as b.Truncate(0).
+// Reset resets the buffer to be empty,
+// but it retains the underlying storage for use by future writes.
+// Reset is the same as Truncate(0).
 func (b *Buffer) Reset() { b.Truncate(0) }
 
 // grow grows the buffer to guarantee space for n more bytes.
index 6245e481805779e8665965053bde7cae4ce31e78..8df62fcc6aec1742a277d5fafd3d4a9705a63d30 100644 (file)
@@ -1255,3 +1255,34 @@ func BenchmarkRepeat(b *testing.B) {
                Repeat([]byte("-"), 80)
        }
 }
+
+func benchmarkBytesCompare(b *testing.B, n int) {
+       var x = make([]byte, n)
+       var y = make([]byte, n)
+
+       for i := 0; i < n; i++ {
+               x[i] = 'a'
+       }
+
+       for i := 0; i < n; i++ {
+               y[i] = 'a'
+       }
+
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               Compare(x, y)
+       }
+}
+
+func BenchmarkBytesCompare1(b *testing.B)    { benchmarkBytesCompare(b, 1) }
+func BenchmarkBytesCompare2(b *testing.B)    { benchmarkBytesCompare(b, 2) }
+func BenchmarkBytesCompare4(b *testing.B)    { benchmarkBytesCompare(b, 4) }
+func BenchmarkBytesCompare8(b *testing.B)    { benchmarkBytesCompare(b, 8) }
+func BenchmarkBytesCompare16(b *testing.B)   { benchmarkBytesCompare(b, 16) }
+func BenchmarkBytesCompare32(b *testing.B)   { benchmarkBytesCompare(b, 32) }
+func BenchmarkBytesCompare64(b *testing.B)   { benchmarkBytesCompare(b, 64) }
+func BenchmarkBytesCompare128(b *testing.B)  { benchmarkBytesCompare(b, 128) }
+func BenchmarkBytesCompare256(b *testing.B)  { benchmarkBytesCompare(b, 256) }
+func BenchmarkBytesCompare512(b *testing.B)  { benchmarkBytesCompare(b, 512) }
+func BenchmarkBytesCompare1024(b *testing.B) { benchmarkBytesCompare(b, 1024) }
+func BenchmarkBytesCompare2048(b *testing.B) { benchmarkBytesCompare(b, 2048) }
index 8bbd1cc52e66e06edf8ec04665b9da2757d9ac03..c3a24c2b76315ca6ad1439694d415e67888be997 100644 (file)
@@ -124,7 +124,7 @@ func (f *File) ReadGo(name string) {
        if f.Ref == nil {
                f.Ref = make([]*Ref, 0, 8)
        }
-       f.walk(ast2, "prog", (*File).saveRef)
+       f.walk(ast2, "prog", (*File).saveExprs)
 
        // Accumulate exported functions.
        // The comments are only on ast1 but we need to
@@ -163,52 +163,72 @@ func commentText(g *ast.CommentGroup) string {
        return strings.Join(pieces, "")
 }
 
+// Save various references we are going to need later.
+func (f *File) saveExprs(x interface{}, context string) {
+       switch x := x.(type) {
+       case *ast.Expr:
+               switch (*x).(type) {
+               case *ast.SelectorExpr:
+                       f.saveRef(x, context)
+               }
+       case *ast.CallExpr:
+               f.saveCall(x)
+       }
+}
+
 // Save references to C.xxx for later processing.
-func (f *File) saveRef(x interface{}, context string) {
-       n, ok := x.(*ast.Expr)
-       if !ok {
+func (f *File) saveRef(n *ast.Expr, context string) {
+       sel := (*n).(*ast.SelectorExpr)
+       // For now, assume that the only instance of capital C is when
+       // used as the imported package identifier.
+       // The parser should take care of scoping in the future, so
+       // that we will be able to distinguish a "top-level C" from a
+       // local C.
+       if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" {
                return
        }
-       if sel, ok := (*n).(*ast.SelectorExpr); ok {
-               // For now, assume that the only instance of capital C is
-               // when used as the imported package identifier.
-               // The parser should take care of scoping in the future,
-               // so that we will be able to distinguish a "top-level C"
-               // from a local C.
-               if l, ok := sel.X.(*ast.Ident); ok && l.Name == "C" {
-                       if context == "as2" {
-                               context = "expr"
-                       }
-                       if context == "embed-type" {
-                               error_(sel.Pos(), "cannot embed C type")
-                       }
-                       goname := sel.Sel.Name
-                       if goname == "errno" {
-                               error_(sel.Pos(), "cannot refer to errno directly; see documentation")
-                               return
-                       }
-                       if goname == "_CMalloc" {
-                               error_(sel.Pos(), "cannot refer to C._CMalloc; use C.malloc")
-                               return
-                       }
-                       if goname == "malloc" {
-                               goname = "_CMalloc"
-                       }
-                       name := f.Name[goname]
-                       if name == nil {
-                               name = &Name{
-                                       Go: goname,
-                               }
-                               f.Name[goname] = name
-                       }
-                       f.Ref = append(f.Ref, &Ref{
-                               Name:    name,
-                               Expr:    n,
-                               Context: context,
-                       })
-                       return
+       if context == "as2" {
+               context = "expr"
+       }
+       if context == "embed-type" {
+               error_(sel.Pos(), "cannot embed C type")
+       }
+       goname := sel.Sel.Name
+       if goname == "errno" {
+               error_(sel.Pos(), "cannot refer to errno directly; see documentation")
+               return
+       }
+       if goname == "_CMalloc" {
+               error_(sel.Pos(), "cannot refer to C._CMalloc; use C.malloc")
+               return
+       }
+       if goname == "malloc" {
+               goname = "_CMalloc"
+       }
+       name := f.Name[goname]
+       if name == nil {
+               name = &Name{
+                       Go: goname,
                }
+               f.Name[goname] = name
+       }
+       f.Ref = append(f.Ref, &Ref{
+               Name:    name,
+               Expr:    n,
+               Context: context,
+       })
+}
+
+// Save calls to C.xxx for later processing.
+func (f *File) saveCall(call *ast.CallExpr) {
+       sel, ok := call.Fun.(*ast.SelectorExpr)
+       if !ok {
+               return
+       }
+       if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" {
+               return
        }
+       f.Calls = append(f.Calls, call)
 }
 
 // If a function should be exported add it to ExpFunc.
index b2a5428f3f4dfac7c42356014e3fd0cc7a85fa4a..bd38a5c153b8e5aabee055a571572da580da25ae 100644 (file)
@@ -117,17 +117,27 @@ The standard C numeric types are available under the names
 C.char, C.schar (signed char), C.uchar (unsigned char),
 C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int),
 C.long, C.ulong (unsigned long), C.longlong (long long),
-C.ulonglong (unsigned long long), C.float, C.double.
+C.ulonglong (unsigned long long), C.float, C.double,
+C.complexfloat (complex float), and C.complexdouble (complex double).
 The C type void* is represented by Go's unsafe.Pointer.
+The C types __int128_t and __uint128_t are represented by [16]byte.
 
 To access a struct, union, or enum type directly, prefix it with
 struct_, union_, or enum_, as in C.struct_stat.
 
+The size of any C type T is available as C.sizeof_T, as in
+C.sizeof_struct_stat.
+
 As Go doesn't have support for C's union type in the general case,
 C's union types are represented as a Go byte array with the same length.
 
 Go structs cannot embed fields with C types.
 
+Go code can not refer to zero-sized fields that occur at the end of
+non-empty C structs.  To get the address of such a field (which is the
+only operation you can do with a zero-sized field) you must take the
+address of the struct and add the size of the struct.
+
 Cgo translates C types into equivalent unexported Go types.
 Because the translations are unexported, a Go package should not
 expose C types in its exported API: a C type used in one Go package
@@ -188,10 +198,10 @@ by making copies of the data.  In pseudo-Go definitions:
        // C string to Go string
        func C.GoString(*C.char) string
 
-       // C string, length to Go string
+       // C data with explicit length to Go string
        func C.GoStringN(*C.char, C.int) string
 
-       // C pointer, length to Go []byte
+       // C data with explicit length to Go []byte
        func C.GoBytes(unsafe.Pointer, C.int) []byte
 
 C references to Go
@@ -221,6 +231,55 @@ definitions and declarations, then the two output files will produce
 duplicate symbols and the linker will fail. To avoid this, definitions
 must be placed in preambles in other files, or in C source files.
 
+Passing pointers
+
+Go is a garbage collected language, and the garbage collector needs to
+know the location of every pointer to Go memory.  Because of this,
+there are restrictions on passing pointers between Go and C.
+
+In this section the term Go pointer means a pointer to memory
+allocated by Go (such as by using the & operator or calling the
+predefined new function) and the term C pointer means a pointer to
+memory allocated by C (such as by a call to C.malloc).  Whether a
+pointer is a Go pointer or a C pointer is a dynamic property
+determined by how the memory was allocated; it has nothing to do with
+the type of the pointer.
+
+Go code may pass a Go pointer to C provided the Go memory to which it
+points does not contain any Go pointers.  The C code must preserve
+this property: it must not store any Go pointers in Go memory, even
+temporarily.  When passing a pointer to a field in a struct, the Go
+memory in question is the memory occupied by the field, not the entire
+struct.  When passing a pointer to an element in an array or slice,
+the Go memory in question is the entire array or the entire backing
+array of the slice.
+
+C code may not keep a copy of a Go pointer after the call returns.
+
+A Go function called by C code may not return a Go pointer.  A Go
+function called by C code may take C pointers as arguments, and it may
+store non-pointer or C pointer data through those pointers, but it may
+not store a Go pointer in memory pointed to by a C pointer.  A Go
+function called by C code may take a Go pointer as an argument, but it
+must preserve the property that the Go memory to which it points does
+not contain any Go pointers.
+
+Go code may not store a Go pointer in C memory.  C code may store Go
+pointers in C memory, subject to the rule above: it must stop storing
+the Go pointer when the C function returns.
+
+These rules are checked dynamically at runtime.  The checking is
+controlled by the cgocheck setting of the GODEBUG environment
+variable.  The default setting is GODEBUG=cgocheck=1, which implements
+reasonably cheap dynamic checks.  These checks may be disabled
+entirely using GODEBUG=cgocheck=0.  Complete checking of pointer
+handling, at some cost in run time, is available via GODEBUG=cgocheck=2.
+
+It is possible to defeat this enforcement by using the unsafe package,
+and of course there is nothing stopping the C code from doing anything
+it likes.  However, programs that break these rules are likely to fail
+in unexpected and unpredictable ways.
+
 Using cgo directly
 
 Usage:
@@ -391,17 +450,13 @@ the translation process.
 
 Translating Go
 
-[The rest of this comment refers to 6g, the Go compiler that is part
-of the amd64 port of the gc Go toolchain. Everything here applies to
-another architecture's compilers as well.]
-
 Given the input Go files x.go and y.go, cgo generates these source
 files:
 
-       x.cgo1.go       # for 6g
-       y.cgo1.go       # for 6g
-       _cgo_gotypes.go # for 6g
-       _cgo_import.go  # for 6g (if -dynout _cgo_import.go)
+       x.cgo1.go       # for gc (cmd/compile)
+       y.cgo1.go       # for gc
+       _cgo_gotypes.go # for gc
+       _cgo_import.go  # for gc (if -dynout _cgo_import.go)
        x.cgo2.c        # for gcc
        y.cgo2.c        # for gcc
        _cgo_defun.c    # for gcc (if -gccgo)
@@ -464,7 +519,7 @@ Linking
 
 Once the _cgo_export.c and *.cgo2.c files have been compiled with gcc,
 they need to be linked into the final binary, along with the libraries
-they might depend on (in the case of puts, stdio). 6l has been
+they might depend on (in the case of puts, stdio). cmd/link has been
 extended to understand basic ELF files, but it does not understand ELF
 in the full complexity that modern C libraries embrace, so it cannot
 in general generate direct references to the system libraries.
@@ -495,23 +550,23 @@ _cgo_import.go, which looks like:
        //go:cgo_import_dynamic _ _ "libc.so.6"
 
 In the end, the compiled Go package, which will eventually be
-presented to 6l as part of a larger program, contains:
+presented to cmd/link as part of a larger program, contains:
 
-       _go_.6        # 6g-compiled object for _cgo_gotypes.go, _cgo_import.go, *.cgo1.go
+       _go_.o        # gc-compiled object for _cgo_gotypes.go, _cgo_import.go, *.cgo1.go
        _all.o        # gcc-compiled object for _cgo_export.c, *.cgo2.c
 
-The final program will be a dynamic executable, so that 6l can avoid
+The final program will be a dynamic executable, so that cmd/link can avoid
 needing to process arbitrary .o files. It only needs to process the .o
 files generated from C files that cgo writes, and those are much more
 limited in the ELF or other features that they use.
 
-In essence, the _cgo_import.6 file includes the extra linking
-directives that 6l is not sophisticated enough to derive from _all.o
+In essence, the _cgo_import.o file includes the extra linking
+directives that cmd/link is not sophisticated enough to derive from _all.o
 on its own. Similarly, the _all.o uses dynamic references to real
-system object code because 6l is not sophisticated enough to process
+system object code because cmd/link is not sophisticated enough to process
 the real code.
 
-The main benefits of this system are that 6l remains relatively simple
+The main benefits of this system are that cmd/link remains relatively simple
 (it does not need to implement a complete ELF and Mach-O linker) and
 that gcc is not needed after the package is compiled. For example,
 package net uses cgo for access to name resolution functions provided
@@ -540,17 +595,17 @@ system calls.
 
 Internal and External Linking
 
-The text above describes "internal" linking, in which 6l parses and
+The text above describes "internal" linking, in which cmd/link parses and
 links host object files (ELF, Mach-O, PE, and so on) into the final
-executable itself. Keeping 6l simple means we cannot possibly
+executable itself. Keeping cmd/link simple means we cannot possibly
 implement the full semantics of the host linker, so the kinds of
 objects that can be linked directly into the binary is limited (other
 code can only be used as a dynamic library). On the other hand, when
-using internal linking, 6l can generate Go binaries by itself.
+using internal linking, cmd/link can generate Go binaries by itself.
 
 In order to allow linking arbitrary object files without requiring
 dynamic libraries, cgo supports an "external" linking mode too. In
-external linking mode, 6l does not process any host object files.
+external linking mode, cmd/link does not process any host object files.
 Instead, it collects all the Go code and writes a single go.o object
 file containing it. Then it invokes the host linker (usually gcc) to
 combine the go.o object file and any supporting non-Go code into a
@@ -582,8 +637,8 @@ to be made when linking the final binary.
 Linking Directives
 
 In either linking mode, package-specific directives must be passed
-through to 6l. These are communicated by writing //go: directives in a
-Go source file compiled by 6g. The directives are copied into the .6
+through to cmd/link. These are communicated by writing //go: directives in a
+Go source file compiled by gc. The directives are copied into the .o
 object file and then processed by the linker.
 
 The directives are:
@@ -672,7 +727,7 @@ Example
 As a simple example, consider a package that uses cgo to call C.sin.
 The following code will be generated by cgo:
 
-       // compiled by 6g
+       // compiled by gc
 
        //go:cgo_ldflag "-lm"
 
@@ -708,7 +763,7 @@ Otherwise the link will be an internal one.
 The linking directives are used according to the kind of final link
 used.
 
-In internal mode, 6l itself processes all the host object files, in
+In internal mode, cmd/link itself processes all the host object files, in
 particular foo.cgo2.o. To do so, it uses the cgo_import_dynamic and
 cgo_dynamic_linker directives to learn that the otherwise undefined
 reference to sin in foo.cgo2.o should be rewritten to refer to the
@@ -716,56 +771,56 @@ symbol sin with version GLIBC_2.2.5 from the dynamic library
 "libm.so.6", and the binary should request "/lib/ld-linux.so.2" as its
 runtime dynamic linker.
 
-In external mode, 6l does not process any host object files, in
-particular foo.cgo2.o. It links together the 6g-generated object
+In external mode, cmd/link does not process any host object files, in
+particular foo.cgo2.o. It links together the gc-generated object
 files, along with any other Go code, into a go.o file. While doing
-that, 6l will discover that there is no definition for
-_cgo_gcc_Cfunc_sin, referred to by the 6g-compiled source file. This
-is okay, because 6l also processes the cgo_import_static directive and
+that, cmd/link will discover that there is no definition for
+_cgo_gcc_Cfunc_sin, referred to by the gc-compiled source file. This
+is okay, because cmd/link also processes the cgo_import_static directive and
 knows that _cgo_gcc_Cfunc_sin is expected to be supplied by a host
-object file, so 6l does not treat the missing symbol as an error when
+object file, so cmd/link does not treat the missing symbol as an error when
 creating go.o. Indeed, the definition for _cgo_gcc_Cfunc_sin will be
 provided to the host linker by foo2.cgo.o, which in turn will need the
-symbol 'sin'. 6l also processes the cgo_ldflag directives, so that it
+symbol 'sin'. cmd/link also processes the cgo_ldflag directives, so that it
 knows that the eventual host link command must include the -lm
 argument, so that the host linker will be able to find 'sin' in the
 math library.
 
-6l Command Line Interface
+cmd/link Command Line Interface
 
-The go command and any other Go-aware build systems invoke 6l
-to link a collection of packages into a single binary. By default, 6l will
+The go command and any other Go-aware build systems invoke cmd/link
+to link a collection of packages into a single binary. By default, cmd/link will
 present the same interface it does today:
 
-       6l main.a
+       cmd/link main.a
 
-produces a file named 6.out, even if 6l does so by invoking the host
+produces a file named a.out, even if cmd/link does so by invoking the host
 linker in external linking mode.
 
-By default, 6l will decide the linking mode as follows: if the only
+By default, cmd/link will decide the linking mode as follows: if the only
 packages using cgo are those on a whitelist of standard library
-packages (net, os/user, runtime/cgo), 6l will use internal linking
-mode. Otherwise, there are non-standard cgo packages involved, and 6l
+packages (net, os/user, runtime/cgo), cmd/link will use internal linking
+mode. Otherwise, there are non-standard cgo packages involved, and cmd/link
 will use external linking mode. The first rule means that a build of
 the godoc binary, which uses net but no other cgo, can run without
 needing gcc available. The second rule means that a build of a
 cgo-wrapped library like sqlite3 can generate a standalone executable
 instead of needing to refer to a dynamic library. The specific choice
-can be overridden using a command line flag: 6l -linkmode=internal or
-6l -linkmode=external.
+can be overridden using a command line flag: cmd/link -linkmode=internal or
+cmd/link -linkmode=external.
 
-In an external link, 6l will create a temporary directory, write any
+In an external link, cmd/link will create a temporary directory, write any
 host object files found in package archives to that directory (renamed
 to avoid conflicts), write the go.o file to that directory, and invoke
 the host linker. The default value for the host linker is $CC, split
 into fields, or else "gcc". The specific host linker command line can
-be overridden using command line flags: 6l -extld=clang
+be overridden using command line flags: cmd/link -extld=clang
 -extldflags='-ggdb -O3'.  If any package in a build includes a .cc or
 other file compiled by the C++ compiler, the go tool will use the
 -extld option to set the host linker to the C++ compiler.
 
 These defaults mean that Go-aware build systems can ignore the linking
-changes and keep running plain '6l' and get reasonable results, but
+changes and keep running plain 'cmd/link' and get reasonable results, but
 they can also control the linking details if desired.
 
 */
index e0b89ec14cb78232a39a673be3d3b5a6f5fb0e27..fb5049c1a1de596916edc9e0c554944ef69aea77 100644 (file)
@@ -38,8 +38,8 @@ var nameToC = map[string]string{
        "ulong":         "unsigned long",
        "longlong":      "long long",
        "ulonglong":     "unsigned long long",
-       "complexfloat":  "float complex",
-       "complexdouble": "double complex",
+       "complexfloat":  "float _Complex",
+       "complexdouble": "double _Complex",
 }
 
 // cname returns the C name to use for C.s.
@@ -167,6 +167,7 @@ func (p *Package) Translate(f *File) {
        if len(needType) > 0 {
                p.loadDWARF(f, needType)
        }
+       p.rewriteCalls(f)
        p.rewriteRef(f)
 }
 
@@ -575,6 +576,331 @@ func (p *Package) mangleName(n *Name) {
        n.Mangle = prefix + n.Kind + "_" + n.Go
 }
 
+// rewriteCalls rewrites all calls that pass pointers to check that
+// they follow the rules for passing pointers between Go and C.
+func (p *Package) rewriteCalls(f *File) {
+       for _, call := range f.Calls {
+               // This is a call to C.xxx; set goname to "xxx".
+               goname := call.Fun.(*ast.SelectorExpr).Sel.Name
+               if goname == "malloc" {
+                       continue
+               }
+               name := f.Name[goname]
+               if name.Kind != "func" {
+                       // Probably a type conversion.
+                       continue
+               }
+               p.rewriteCall(f, call, name)
+       }
+}
+
+// rewriteCall rewrites one call to add pointer checks.  We replace
+// each pointer argument x with _cgoCheckPointer(x).(T).
+func (p *Package) rewriteCall(f *File, call *ast.CallExpr, name *Name) {
+       for i, param := range name.FuncType.Params {
+               if len(call.Args) <= i {
+                       // Avoid a crash; this will be caught when the
+                       // generated file is compiled.
+                       return
+               }
+
+               // An untyped nil does not need a pointer check, and
+               // when _cgoCheckPointer returns the untyped nil the
+               // type assertion we are going to insert will fail.
+               // Easier to just skip nil arguments.
+               // TODO: Note that this fails if nil is shadowed.
+               if id, ok := call.Args[i].(*ast.Ident); ok && id.Name == "nil" {
+                       continue
+               }
+
+               if !p.needsPointerCheck(f, param.Go) {
+                       continue
+               }
+
+               c := &ast.CallExpr{
+                       Fun: ast.NewIdent("_cgoCheckPointer"),
+                       Args: []ast.Expr{
+                               call.Args[i],
+                       },
+               }
+
+               // Add optional additional arguments for an address
+               // expression.
+               c.Args = p.checkAddrArgs(f, c.Args, call.Args[i])
+
+               // _cgoCheckPointer returns interface{}.
+               // We need to type assert that to the type we want.
+               // If the Go version of this C type uses
+               // unsafe.Pointer, we can't use a type assertion,
+               // because the Go file might not import unsafe.
+               // Instead we use a local variant of _cgoCheckPointer.
+
+               var arg ast.Expr
+               if n := p.unsafeCheckPointerName(param.Go); n != "" {
+                       c.Fun = ast.NewIdent(n)
+                       arg = c
+               } else {
+                       // In order for the type assertion to succeed,
+                       // we need it to match the actual type of the
+                       // argument.  The only type we have is the
+                       // type of the function parameter.  We know
+                       // that the argument type must be assignable
+                       // to the function parameter type, or the code
+                       // would not compile, but there is nothing
+                       // requiring that the types be exactly the
+                       // same.  Add a type conversion to the
+                       // argument so that the type assertion will
+                       // succeed.
+                       c.Args[0] = &ast.CallExpr{
+                               Fun: param.Go,
+                               Args: []ast.Expr{
+                                       c.Args[0],
+                               },
+                       }
+
+                       arg = &ast.TypeAssertExpr{
+                               X:    c,
+                               Type: param.Go,
+                       }
+               }
+
+               call.Args[i] = arg
+       }
+}
+
+// needsPointerCheck returns whether the type t needs a pointer check.
+// This is true if t is a pointer and if the value to which it points
+// might contain a pointer.
+func (p *Package) needsPointerCheck(f *File, t ast.Expr) bool {
+       return p.hasPointer(f, t, true)
+}
+
+// hasPointer is used by needsPointerCheck.  If top is true it returns
+// whether t is or contains a pointer that might point to a pointer.
+// If top is false it returns whether t is or contains a pointer.
+// f may be nil.
+func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
+       switch t := t.(type) {
+       case *ast.ArrayType:
+               if t.Len == nil {
+                       if !top {
+                               return true
+                       }
+                       return p.hasPointer(f, t.Elt, false)
+               }
+               return p.hasPointer(f, t.Elt, top)
+       case *ast.StructType:
+               for _, field := range t.Fields.List {
+                       if p.hasPointer(f, field.Type, top) {
+                               return true
+                       }
+               }
+               return false
+       case *ast.StarExpr: // Pointer type.
+               if !top {
+                       return true
+               }
+               return p.hasPointer(f, t.X, false)
+       case *ast.FuncType, *ast.InterfaceType, *ast.MapType, *ast.ChanType:
+               return true
+       case *ast.Ident:
+               // TODO: Handle types defined within function.
+               for _, d := range p.Decl {
+                       gd, ok := d.(*ast.GenDecl)
+                       if !ok || gd.Tok != token.TYPE {
+                               continue
+                       }
+                       for _, spec := range gd.Specs {
+                               ts, ok := spec.(*ast.TypeSpec)
+                               if !ok {
+                                       continue
+                               }
+                               if ts.Name.Name == t.Name {
+                                       return p.hasPointer(f, ts.Type, top)
+                               }
+                       }
+               }
+               if def := typedef[t.Name]; def != nil {
+                       return p.hasPointer(f, def.Go, top)
+               }
+               if t.Name == "string" {
+                       return !top
+               }
+               if t.Name == "error" {
+                       return true
+               }
+               if goTypes[t.Name] != nil {
+                       return false
+               }
+               // We can't figure out the type.  Conservative
+               // approach is to assume it has a pointer.
+               return true
+       case *ast.SelectorExpr:
+               if l, ok := t.X.(*ast.Ident); !ok || l.Name != "C" {
+                       // Type defined in a different package.
+                       // Conservative approach is to assume it has a
+                       // pointer.
+                       return true
+               }
+               if f == nil {
+                       // Conservative approach: assume pointer.
+                       return true
+               }
+               name := f.Name[t.Sel.Name]
+               if name != nil && name.Kind == "type" && name.Type != nil && name.Type.Go != nil {
+                       return p.hasPointer(f, name.Type.Go, top)
+               }
+               // We can't figure out the type.  Conservative
+               // approach is to assume it has a pointer.
+               return true
+       default:
+               error_(t.Pos(), "could not understand type %s", gofmt(t))
+               return true
+       }
+}
+
+// checkAddrArgs tries to add arguments to the call of
+// _cgoCheckPointer when the argument is an address expression.  We
+// pass true to mean that the argument is an address operation of
+// something other than a slice index, which means that it's only
+// necessary to check the specific element pointed to, not the entire
+// object.  This is for &s.f, where f is a field in a struct.  We can
+// pass a slice or array, meaning that we should check the entire
+// slice or array but need not check any other part of the object.
+// This is for &s.a[i], where we need to check all of a.  However, we
+// only pass the slice or array if we can refer to it without side
+// effects.
+func (p *Package) checkAddrArgs(f *File, args []ast.Expr, x ast.Expr) []ast.Expr {
+       // Strip type conversions.
+       for {
+               c, ok := x.(*ast.CallExpr)
+               if !ok || len(c.Args) != 1 || !p.isType(c.Fun) {
+                       break
+               }
+               x = c.Args[0]
+       }
+       u, ok := x.(*ast.UnaryExpr)
+       if !ok || u.Op != token.AND {
+               return args
+       }
+       index, ok := u.X.(*ast.IndexExpr)
+       if !ok {
+               // This is the address of something that is not an
+               // index expression.  We only need to examine the
+               // single value to which it points.
+               // TODO: what if true is shadowed?
+               return append(args, ast.NewIdent("true"))
+       }
+       if !p.hasSideEffects(f, index.X) {
+               // Examine the entire slice.
+               return append(args, index.X)
+       }
+       // Treat the pointer as unknown.
+       return args
+}
+
+// hasSideEffects returns whether the expression x has any side
+// effects.  x is an expression, not a statement, so the only side
+// effect is a function call.
+func (p *Package) hasSideEffects(f *File, x ast.Expr) bool {
+       found := false
+       f.walk(x, "expr",
+               func(f *File, x interface{}, context string) {
+                       switch x.(type) {
+                       case *ast.CallExpr:
+                               found = true
+                       }
+               })
+       return found
+}
+
+// isType returns whether the expression is definitely a type.
+// This is conservative--it returns false for an unknown identifier.
+func (p *Package) isType(t ast.Expr) bool {
+       switch t := t.(type) {
+       case *ast.SelectorExpr:
+               if t.Sel.Name != "Pointer" {
+                       return false
+               }
+               id, ok := t.X.(*ast.Ident)
+               if !ok {
+                       return false
+               }
+               return id.Name == "unsafe"
+       case *ast.Ident:
+               // TODO: This ignores shadowing.
+               switch t.Name {
+               case "unsafe.Pointer", "bool", "byte",
+                       "complex64", "complex128",
+                       "error",
+                       "float32", "float64",
+                       "int", "int8", "int16", "int32", "int64",
+                       "rune", "string",
+                       "uint", "uint8", "uint16", "uint32", "uint64", "uintptr":
+
+                       return true
+               }
+       case *ast.StarExpr:
+               return p.isType(t.X)
+       case *ast.ArrayType, *ast.StructType, *ast.FuncType, *ast.InterfaceType,
+               *ast.MapType, *ast.ChanType:
+
+               return true
+       }
+       return false
+}
+
+// unsafeCheckPointerName is given the Go version of a C type.  If the
+// type uses unsafe.Pointer, we arrange to build a version of
+// _cgoCheckPointer that returns that type.  This avoids using a type
+// assertion to unsafe.Pointer in our copy of user code.  We return
+// the name of the _cgoCheckPointer function we are going to build, or
+// the empty string if the type does not use unsafe.Pointer.
+func (p *Package) unsafeCheckPointerName(t ast.Expr) string {
+       if !p.hasUnsafePointer(t) {
+               return ""
+       }
+       var buf bytes.Buffer
+       conf.Fprint(&buf, fset, t)
+       s := buf.String()
+       for i, t := range p.CgoChecks {
+               if s == t {
+                       return p.unsafeCheckPointerNameIndex(i)
+               }
+       }
+       p.CgoChecks = append(p.CgoChecks, s)
+       return p.unsafeCheckPointerNameIndex(len(p.CgoChecks) - 1)
+}
+
+// hasUnsafePointer returns whether the Go type t uses unsafe.Pointer.
+// t is the Go version of a C type, so we don't need to handle every case.
+// We only care about direct references, not references via typedefs.
+func (p *Package) hasUnsafePointer(t ast.Expr) bool {
+       switch t := t.(type) {
+       case *ast.Ident:
+               // We don't see a SelectorExpr for unsafe.Pointer;
+               // this is created by code in this file.
+               return t.Name == "unsafe.Pointer"
+       case *ast.ArrayType:
+               return p.hasUnsafePointer(t.Elt)
+       case *ast.StructType:
+               for _, f := range t.Fields.List {
+                       if p.hasUnsafePointer(f.Type) {
+                               return true
+                       }
+               }
+       case *ast.StarExpr: // Pointer type.
+               return p.hasUnsafePointer(t.X)
+       }
+       return false
+}
+
+// unsafeCheckPointerNameIndex returns the name to use for a
+// _cgoCheckPointer variant based on the index in the CgoChecks slice.
+func (p *Package) unsafeCheckPointerNameIndex(i int) string {
+       return fmt.Sprintf("_cgoCheckPointer%d", i)
+}
+
 // rewriteRef rewrites all the C.xxx references in f.AST to refer to the
 // Go equivalents, now that we have figured out the meaning of all
 // the xxx.  In *godefs mode, rewriteRef replaces the names
@@ -612,6 +938,10 @@ func (p *Package) rewriteRef(f *File) {
                        if r.Name.Kind != "func" {
                                if r.Name.Kind == "type" {
                                        r.Context = "type"
+                                       if r.Name.Type == nil {
+                                               error_(r.Pos(), "invalid conversion to C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
+                                               break
+                                       }
                                        expr = r.Name.Type.Go
                                        break
                                }
@@ -663,6 +993,10 @@ func (p *Package) rewriteRef(f *File) {
                                }
                        } else if r.Name.Kind == "type" {
                                // Okay - might be new(T)
+                               if r.Name.Type == nil {
+                                       error_(r.Pos(), "expression C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
+                                       break
+                               }
                                expr = r.Name.Type.Go
                        } else if r.Name.Kind == "var" {
                                expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
@@ -1028,12 +1362,12 @@ var dwarfToName = map[string]string{
        "long unsigned int":      "ulong",
        "unsigned int":           "uint",
        "short unsigned int":     "ushort",
+       "unsigned short":         "ushort", // Used by Clang; issue 13129.
        "short int":              "short",
        "long long int":          "longlong",
        "long long unsigned int": "ulonglong",
        "signed char":            "schar",
-       "float complex":          "complexfloat",
-       "double complex":         "complexdouble",
+       "unsigned char":          "uchar",
 }
 
 const signedDelta = 64
@@ -1224,6 +1558,11 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
                        t.Go = c.int32
                case 8:
                        t.Go = c.int64
+               case 16:
+                       t.Go = &ast.ArrayType{
+                               Len: c.intExpr(t.Size),
+                               Elt: c.uint8,
+                       }
                }
                if t.Align = t.Size; t.Align >= c.ptrSize {
                        t.Align = c.ptrSize
@@ -1381,6 +1720,11 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
                        t.Go = c.uint32
                case 8:
                        t.Go = c.uint64
+               case 16:
+                       t.Go = &ast.ArrayType{
+                               Len: c.intExpr(t.Size),
+                               Elt: c.uint8,
+                       }
                }
                if t.Align = t.Size; t.Align >= c.ptrSize {
                        t.Align = c.ptrSize
@@ -1393,7 +1737,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
        }
 
        switch dtype.(type) {
-       case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
+       case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.ComplexType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
                s := dtype.Common().Name
                if s != "" {
                        if ss, ok := dwarfToName[s]; ok {
index 1b0ece29ef4895d03aa3ca7d2eb3550c3e16d694..aff616ea5788408753d0ed4065bc07e401709c13 100644 (file)
@@ -11,6 +11,7 @@ import (
        "go/printer"
        "go/token"
        "os"
+       "path/filepath"
        "strings"
 )
 
@@ -19,7 +20,7 @@ func (p *Package) godefs(f *File, srcfile string) string {
        var buf bytes.Buffer
 
        fmt.Fprintf(&buf, "// Created by cgo -godefs - DO NOT EDIT\n")
-       fmt.Fprintf(&buf, "// %s\n", strings.Join(os.Args, " "))
+       fmt.Fprintf(&buf, "// %s %s\n", filepath.Base(os.Args[0]), strings.Join(os.Args[1:], " "))
        fmt.Fprintf(&buf, "\n")
 
        override := make(map[string]string)
index c8cd1610baf221f3f5d644d4e61f43e99225dce4..6171b9d0672153733214c7f19571b7de7d7c272c 100644 (file)
@@ -42,6 +42,7 @@ type Package struct {
        GoFiles     []string // list of Go files
        GccFiles    []string // list of gcc output files
        Preamble    string   // collected preamble for _cgo_export.h
+       CgoChecks   []string // see unsafeCheckPointerName
 }
 
 // A File collects information about a single Go input file.
@@ -51,6 +52,7 @@ type File struct {
        Package  string              // Package name
        Preamble string              // C preamble (doc comment on import "C")
        Ref      []*Ref              // all references to C.xxx in AST
+       Calls    []*ast.CallExpr     // all calls to C.xxx in AST
        ExpFunc  []*ExpFunc          // exported functions for this file
        Name     map[string]*Name    // map from Go name to Name
 }
@@ -132,43 +134,47 @@ func usage() {
 }
 
 var ptrSizeMap = map[string]int64{
-       "386":     4,
-       "alpha":   8,
-       "amd64":   8,
-       "arm":     4,
-       "arm64":   8,
-       "m68k":    4,
-       "mipso32": 4,
-       "mipsn32": 4,
-       "mipso64": 8,
-       "mipsn64": 8,
-       "ppc":     4,
-       "ppc64":   8,
-       "ppc64le": 8,
-       "s390":    4,
-       "s390x":   8,
-       "sparc":   4,
-       "sparc64": 8,
+       "386":      4,
+       "alpha":    8,
+       "amd64":    8,
+       "arm":      4,
+       "arm64":    8,
+       "m68k":     4,
+       "mipso32":  4,
+       "mipsn32":  4,
+       "mipso64":  8,
+       "mipsn64":  8,
+       "mips64":   8,
+       "mips64le": 8,
+       "ppc":      4,
+       "ppc64":    8,
+       "ppc64le":  8,
+       "s390":     4,
+       "s390x":    8,
+       "sparc":    4,
+       "sparc64":  8,
 }
 
 var intSizeMap = map[string]int64{
-       "386":     4,
-       "alpha":   8,
-       "amd64":   8,
-       "arm":     4,
-       "arm64":   8,
-       "m68k":    4,
-       "mipso32": 4,
-       "mipsn32": 4,
-       "mipso64": 8,
-       "mipsn64": 8,
-       "ppc":     4,
-       "ppc64":   8,
-       "ppc64le": 8,
-       "s390":    4,
-       "s390x":   8,
-       "sparc":   4,
-       "sparc64": 8,
+       "386":      4,
+       "alpha":    8,
+       "amd64":    8,
+       "arm":      4,
+       "arm64":    8,
+       "m68k":     4,
+       "mipso32":  4,
+       "mipsn32":  4,
+       "mipso64":  8,
+       "mipsn64":  8,
+       "mips64":   8,
+       "mips64le": 8,
+       "ppc":      4,
+       "ppc64":    8,
+       "ppc64le":  8,
+       "s390":     4,
+       "s390x":    8,
+       "sparc":    4,
+       "sparc64":  8,
 }
 
 var cPrefix string
@@ -297,11 +303,7 @@ func main() {
                if nerrors > 0 {
                        os.Exit(2)
                }
-               pkg := f.Package
-               if dir := os.Getenv("CGOPKGPATH"); dir != "" {
-                       pkg = filepath.Join(dir, pkg)
-               }
-               p.PackagePath = pkg
+               p.PackagePath = f.Package
                p.Record(f)
                if *godefs {
                        os.Stdout.WriteString(p.godefs(f, input))
index 90a744196228e1e93c53e97a01984adb64efde02..ca0ec0aaa28e99023bedcbbdbd931aa423b4d616 100644 (file)
@@ -103,11 +103,19 @@ func (p *Package) writeDefs() {
        }
 
        if *gccgo {
+               fmt.Fprint(fgo2, gccgoGoProlog)
                fmt.Fprint(fc, p.cPrologGccgo())
        } else {
                fmt.Fprint(fgo2, goProlog)
        }
 
+       for i, t := range p.CgoChecks {
+               n := p.unsafeCheckPointerNameIndex(i)
+               fmt.Fprintf(fgo2, "\nfunc %s(p interface{}, args ...interface{}) %s {\n", n, t)
+               fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t)
+               fmt.Fprintf(fgo2, "}\n")
+       }
+
        gccgoSymbolPrefix := p.gccgoSymbolPrefix()
 
        cVars := make(map[string]bool)
@@ -693,7 +701,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
                }
                fntype := fn.Type
                forFieldList(fntype.Params,
-                       func(i int, atype ast.Expr) {
+                       func(i int, aname string, atype ast.Expr) {
                                t := p.cgoType(atype)
                                if off%t.Align != 0 {
                                        pad := t.Align - off%t.Align
@@ -711,7 +719,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
                        npad++
                }
                forFieldList(fntype.Results,
-                       func(i int, atype ast.Expr) {
+                       func(i int, aname string, atype ast.Expr) {
                                t := p.cgoType(atype)
                                if off%t.Align != 0 {
                                        pad := t.Align - off%t.Align
@@ -744,8 +752,12 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
                        fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
                        fmt.Fprintf(fgcch, "struct %s_return {\n", exp.ExpName)
                        forFieldList(fntype.Results,
-                               func(i int, atype ast.Expr) {
-                                       fmt.Fprintf(fgcch, "\t%s r%d;\n", p.cgoType(atype).C, i)
+                               func(i int, aname string, atype ast.Expr) {
+                                       fmt.Fprintf(fgcch, "\t%s r%d;", p.cgoType(atype).C, i)
+                                       if len(aname) > 0 {
+                                               fmt.Fprintf(fgcch, " /* %s */", aname)
+                                       }
+                                       fmt.Fprint(fgcch, "\n")
                                })
                        fmt.Fprintf(fgcch, "};\n")
                        gccResult = "struct " + exp.ExpName + "_return"
@@ -758,7 +770,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
                        s += " recv"
                }
                forFieldList(fntype.Params,
-                       func(i int, atype ast.Expr) {
+                       func(i int, aname string, atype ast.Expr) {
                                if i > 0 || fn.Recv != nil {
                                        s += ", "
                                }
@@ -783,7 +795,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
                        fmt.Fprintf(fgcc, "\ta.recv = recv;\n")
                }
                forFieldList(fntype.Params,
-                       func(i int, atype ast.Expr) {
+                       func(i int, aname string, atype ast.Expr) {
                                fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i)
                        })
                fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d);\n", cPrefix, exp.ExpName, off)
@@ -792,7 +804,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
                                fmt.Fprintf(fgcc, "\treturn a.r0;\n")
                        } else {
                                forFieldList(fntype.Results,
-                                       func(i int, atype ast.Expr) {
+                                       func(i int, aname string, atype ast.Expr) {
                                                fmt.Fprintf(fgcc, "\tr.r%d = a.r%d;\n", i, i)
                                        })
                                fmt.Fprintf(fgcc, "\treturn r;\n")
@@ -800,17 +812,18 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
                }
                fmt.Fprintf(fgcc, "}\n")
 
-               // Build the wrapper function compiled by gc.
-               goname := exp.Func.Name.Name
+               // Build the wrapper function compiled by cmd/compile.
+               goname := "_cgoexpwrap" + cPrefix + "_"
                if fn.Recv != nil {
-                       goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
+                       goname += fn.Recv.List[0].Names[0].Name + "_"
                }
-               fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", goname)
+               goname += exp.Func.Name.Name
+               fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.ExpName)
                fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
                fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
                fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
                fmt.Fprintf(fgo2, "//go:norace\n")  // must not have race detector calls inserted
-               fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32) {", cPrefix, exp.ExpName)
+               fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32) {\n", cPrefix, exp.ExpName)
                fmt.Fprintf(fgo2, "\tfn := %s\n", goname)
                // The indirect here is converting from a Go function pointer to a C function pointer.
                fmt.Fprintf(fgo2, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n));\n")
@@ -818,44 +831,75 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
 
                fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
 
-               // Calling a function with a receiver from C requires
-               // a Go wrapper function.
+               // This code uses printer.Fprint, not conf.Fprint,
+               // because we don't want //line comments in the middle
+               // of the function types.
+               fmt.Fprintf(fgo2, "\n")
+               fmt.Fprintf(fgo2, "func %s(", goname)
+               comma := false
                if fn.Recv != nil {
-                       fmt.Fprintf(fgo2, "func %s(recv ", goname)
-                       conf.Fprint(fgo2, fset, fn.Recv.List[0].Type)
-                       forFieldList(fntype.Params,
-                               func(i int, atype ast.Expr) {
-                                       fmt.Fprintf(fgo2, ", p%d ", i)
-                                       conf.Fprint(fgo2, fset, atype)
-                               })
-                       fmt.Fprintf(fgo2, ")")
-                       if gccResult != "void" {
-                               fmt.Fprint(fgo2, " (")
-                               forFieldList(fntype.Results,
-                                       func(i int, atype ast.Expr) {
-                                               if i > 0 {
-                                                       fmt.Fprint(fgo2, ", ")
-                                               }
-                                               conf.Fprint(fgo2, fset, atype)
-                                       })
-                               fmt.Fprint(fgo2, ")")
-                       }
-                       fmt.Fprint(fgo2, " {\n")
-                       fmt.Fprint(fgo2, "\t")
-                       if gccResult != "void" {
-                               fmt.Fprint(fgo2, "return ")
-                       }
-                       fmt.Fprintf(fgo2, "recv.%s(", exp.Func.Name)
-                       forFieldList(fntype.Params,
-                               func(i int, atype ast.Expr) {
+                       fmt.Fprintf(fgo2, "recv ")
+                       printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
+                       comma = true
+               }
+               forFieldList(fntype.Params,
+                       func(i int, aname string, atype ast.Expr) {
+                               if comma {
+                                       fmt.Fprintf(fgo2, ", ")
+                               }
+                               fmt.Fprintf(fgo2, "p%d ", i)
+                               printer.Fprint(fgo2, fset, atype)
+                               comma = true
+                       })
+               fmt.Fprintf(fgo2, ")")
+               if gccResult != "void" {
+                       fmt.Fprint(fgo2, " (")
+                       forFieldList(fntype.Results,
+                               func(i int, aname string, atype ast.Expr) {
                                        if i > 0 {
                                                fmt.Fprint(fgo2, ", ")
                                        }
-                                       fmt.Fprintf(fgo2, "p%d", i)
+                                       fmt.Fprintf(fgo2, "r%d ", i)
+                                       printer.Fprint(fgo2, fset, atype)
                                })
-                       fmt.Fprint(fgo2, ")\n")
-                       fmt.Fprint(fgo2, "}\n")
+                       fmt.Fprint(fgo2, ")")
                }
+               fmt.Fprint(fgo2, " {\n")
+               if gccResult == "void" {
+                       fmt.Fprint(fgo2, "\t")
+               } else {
+                       // Verify that any results don't contain any
+                       // Go pointers.
+                       addedDefer := false
+                       forFieldList(fntype.Results,
+                               func(i int, aname string, atype ast.Expr) {
+                                       if !p.hasPointer(nil, atype, false) {
+                                               return
+                                       }
+                                       if !addedDefer {
+                                               fmt.Fprint(fgo2, "\tdefer func() {\n")
+                                               addedDefer = true
+                                       }
+                                       fmt.Fprintf(fgo2, "\t\t_cgoCheckResult(r%d)\n", i)
+                               })
+                       if addedDefer {
+                               fmt.Fprint(fgo2, "\t}()\n")
+                       }
+                       fmt.Fprint(fgo2, "\treturn ")
+               }
+               if fn.Recv != nil {
+                       fmt.Fprintf(fgo2, "recv.")
+               }
+               fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
+               forFieldList(fntype.Params,
+                       func(i int, aname string, atype ast.Expr) {
+                               if i > 0 {
+                                       fmt.Fprint(fgo2, ", ")
+                               }
+                               fmt.Fprintf(fgo2, "p%d", i)
+                       })
+               fmt.Fprint(fgo2, ")\n")
+               fmt.Fprint(fgo2, "}\n")
        }
 
        fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
@@ -879,13 +923,13 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
                cdeclBuf := new(bytes.Buffer)
                resultCount := 0
                forFieldList(fntype.Results,
-                       func(i int, atype ast.Expr) { resultCount++ })
+                       func(i int, aname string, atype ast.Expr) { resultCount++ })
                switch resultCount {
                case 0:
                        fmt.Fprintf(cdeclBuf, "void")
                case 1:
                        forFieldList(fntype.Results,
-                               func(i int, atype ast.Expr) {
+                               func(i int, aname string, atype ast.Expr) {
                                        t := p.cgoType(atype)
                                        fmt.Fprintf(cdeclBuf, "%s", t.C)
                                })
@@ -894,9 +938,13 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
                        fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
                        fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName)
                        forFieldList(fntype.Results,
-                               func(i int, atype ast.Expr) {
+                               func(i int, aname string, atype ast.Expr) {
                                        t := p.cgoType(atype)
-                                       fmt.Fprintf(fgcch, "\t%s r%d;\n", t.C, i)
+                                       fmt.Fprintf(fgcch, "\t%s r%d;", t.C, i)
+                                       if len(aname) > 0 {
+                                               fmt.Fprintf(fgcch, " /* %s */", aname)
+                                       }
+                                       fmt.Fprint(fgcch, "\n")
                                })
                        fmt.Fprintf(fgcch, "};\n")
                        fmt.Fprintf(cdeclBuf, "struct %s_result", exp.ExpName)
@@ -911,7 +959,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
                }
                // Function parameters.
                forFieldList(fntype.Params,
-                       func(i int, atype ast.Expr) {
+                       func(i int, aname string, atype ast.Expr) {
                                if i > 0 || fn.Recv != nil {
                                        fmt.Fprintf(cdeclBuf, ", ")
                                }
@@ -925,23 +973,15 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
                        fmt.Fprintf(fgcch, "\n%s", exp.Doc)
                }
 
+               fmt.Fprintf(fgcch, "extern %s %s %s;\n", cRet, exp.ExpName, cParams)
+
                // We need to use a name that will be exported by the
                // Go code; otherwise gccgo will make it static and we
                // will not be able to link against it from the C
                // code.
                goName := "Cgoexp_" + exp.ExpName
-               fmt.Fprintf(fgcch, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
-               fmt.Fprint(fgcch, "\n")
-
-               // Use a #define so that the C code that includes
-               // cgo_export.h will be able to refer to the Go
-               // function using the expected name.
-               fmt.Fprintf(fgcch, "#define %s %s\n", exp.ExpName, goName)
-
-               // Use a #undef in _cgo_export.c so that we ignore the
-               // #define from cgo_export.h, since here we are
-               // defining the real function.
-               fmt.Fprintf(fgcc, "#undef %s\n", exp.ExpName)
+               fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
+               fmt.Fprint(fgcc, "\n")
 
                fmt.Fprint(fgcc, "\n")
                fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
@@ -956,7 +996,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
                        fmt.Fprint(fgcc, "recv")
                }
                forFieldList(fntype.Params,
-                       func(i int, atype ast.Expr) {
+                       func(i int, aname string, atype ast.Expr) {
                                if i > 0 || fn.Recv != nil {
                                        fmt.Fprintf(fgcc, ", ")
                                }
@@ -982,7 +1022,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
                        printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
                }
                forFieldList(fntype.Params,
-                       func(i int, atype ast.Expr) {
+                       func(i int, aname string, atype ast.Expr) {
                                if i > 0 || fn.Recv != nil {
                                        fmt.Fprintf(fgo2, ", ")
                                }
@@ -993,7 +1033,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
                if resultCount > 0 {
                        fmt.Fprintf(fgo2, " (")
                        forFieldList(fntype.Results,
-                               func(i int, atype ast.Expr) {
+                               func(i int, aname string, atype ast.Expr) {
                                        if i > 0 {
                                                fmt.Fprint(fgo2, ", ")
                                        }
@@ -1013,7 +1053,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
                }
                fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
                forFieldList(fntype.Params,
-                       func(i int, atype ast.Expr) {
+                       func(i int, aname string, atype ast.Expr) {
                                if i > 0 {
                                        fmt.Fprint(fgo2, ", ")
                                }
@@ -1071,19 +1111,19 @@ func (p *Package) gccgoSymbolPrefix() string {
 }
 
 // Call a function for each entry in an ast.FieldList, passing the
-// index into the list and the type.
-func forFieldList(fl *ast.FieldList, fn func(int, ast.Expr)) {
+// index into the list, the name if any, and the type.
+func forFieldList(fl *ast.FieldList, fn func(int, string, ast.Expr)) {
        if fl == nil {
                return
        }
        i := 0
        for _, r := range fl.List {
                if r.Names == nil {
-                       fn(i, r.Type)
+                       fn(i, "", r.Type)
                        i++
                } else {
-                       for range r.Names {
-                               fn(i, r.Type)
+                       for _, n := range r.Names {
+                               fn(i, n.Name, r.Type)
                                i++
                        }
                }
@@ -1193,9 +1233,11 @@ func (p *Package) cgoType(e ast.Expr) *Type {
 }
 
 const gccProlog = `
-// Usual nonsense: if x and y are not equal, the type will be invalid
-// (have a negative array count) and an inscrutable error will come
-// out of the compiler and hopefully mention "name".
+/*
+  If x and y are not equal, the type will be invalid
+  (have a negative array count) and an inscrutable error will come
+  out of the compiler and hopefully mention "name".
+*/
 #define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];
 
 // Check at compile time that the sizes we use match our expectations.
@@ -1239,6 +1281,18 @@ func _cgo_runtime_cmalloc(uintptr) unsafe.Pointer
 
 //go:linkname _cgo_runtime_cgocallback runtime.cgocallback
 func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr)
+
+//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
+func _cgoCheckPointer(interface{}, ...interface{}) interface{}
+
+//go:linkname _cgoCheckResult runtime.cgoCheckResult
+func _cgoCheckResult(interface{})
+`
+
+const gccgoGoProlog = `
+func _cgoCheckPointer(interface{}, ...interface{}) interface{}
+
+func _cgoCheckResult(interface{})
 `
 
 const goStringDef = `
@@ -1293,7 +1347,8 @@ var builtinDefs = map[string]string{
 }
 
 func (p *Package) cPrologGccgo() string {
-       return strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1)
+       return strings.Replace(strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1),
+               "GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(), -1)
 }
 
 const cPrologGccgo = `
@@ -1348,6 +1403,39 @@ void *_cgoPREFIX_Cfunc__CMalloc(size_t n) {
                 runtime_throw("runtime: C malloc failed");
         return p;
 }
+
+struct __go_type_descriptor;
+typedef struct __go_empty_interface {
+       const struct __go_type_descriptor *__type_descriptor;
+       void *__object;
+} Eface;
+
+extern Eface runtimeCgoCheckPointer(Eface, Slice)
+       __asm__("runtime.cgoCheckPointer")
+       __attribute__((weak));
+
+extern Eface localCgoCheckPointer(Eface, Slice)
+       __asm__("GCCGOSYMBOLPREF._cgoCheckPointer");
+
+Eface localCgoCheckPointer(Eface ptr, Slice args) {
+       if(runtimeCgoCheckPointer) {
+               return runtimeCgoCheckPointer(ptr, args);
+       }
+       return ptr;
+}
+
+extern void runtimeCgoCheckResult(Eface)
+       __asm__("runtime.cgoCheckResult")
+       __attribute__((weak));
+
+extern void localCgoCheckResult(Eface)
+       __asm__("GCCGOSYMBOLPREF._cgoCheckResult");
+
+void localCgoCheckResult(Eface val) {
+       if(runtimeCgoCheckResult) {
+               runtimeCgoCheckResult(val);
+       }
+}
 `
 
 func (p *Package) gccExportHeaderProlog() string {
@@ -1373,14 +1461,16 @@ typedef GoUintGOINTBITS GoUint;
 typedef __SIZE_TYPE__ GoUintptr;
 typedef float GoFloat32;
 typedef double GoFloat64;
-typedef __complex float GoComplex64;
-typedef __complex double GoComplex128;
+typedef float _Complex GoComplex64;
+typedef double _Complex GoComplex128;
 
-// static assertion to make sure the file is being used on architecture
-// at least with matching size of GoInt.
+/*
+  static assertion to make sure the file is being used on architecture
+  at least with matching size of GoInt.
+*/
 typedef char _check_for_GOINTBITS_bit_pointer_matching_GoInt[sizeof(void*)==GOINTBITS/8 ? 1:-1];
 
-typedef struct { char *p; GoInt n; } GoString;
+typedef struct { const char *p; GoInt n; } GoString;
 typedef void *GoMap;
 typedef void *GoChan;
 typedef struct { void *t; void *v; } GoInterface;
index 1134997eaaa277f0b0f6592a23c615438b97b327..5db4bc6beca4d4d9a31791a26a96e5fa112719e9 100644 (file)
@@ -84,12 +84,16 @@ and test commands:
        -n
                print the commands but do not run them.
        -p n
-               the number of builds that can be run in parallel.
+               the number of programs, such as build commands or
+               test binaries, that can be run in parallel.
                The default is the number of CPUs available, except
                on darwin/arm which defaults to 1.
        -race
                enable data race detection.
                Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
+       -msan
+               enable interoperation with memory sanitizer.
+               Supported only on linux/amd64.
        -v
                print the names of packages as they are compiled.
        -work
@@ -112,13 +116,14 @@ and test commands:
                a suffix to use in the name of the package installation directory,
                in order to keep output separate from default builds.
                If using the -race flag, the install suffix is automatically set to race
-               or, if set explicitly, has _race appended to it.  Using a -buildmode
-               option that requires non-default compile flags has a similar effect.
+               or, if set explicitly, has _race appended to it.  Likewise for the -msan
+               flag.  Using a -buildmode option that requires non-default compile flags
+               has a similar effect.
        -ldflags 'flag list'
                arguments to pass on each go tool link invocation.
        -linkshared
                link against shared libraries previously created with
-               -buildmode=shared
+               -buildmode=shared.
        -pkgdir dir
                install and load all packages from dir instead of the usual locations.
                For example, when building with a non-standard configuration,
@@ -225,12 +230,17 @@ which is schematically one of these:
 
        go doc <pkg>
        go doc <sym>[.<method>]
-       go doc [<pkg>].<sym>[.<method>]
+       go doc [<pkg>.]<sym>[.<method>]
+       go doc [<pkg>.][<sym>.]<method>
 
-The first item in this list matched by the argument is the one whose
-documentation is printed. (See the examples below.) For packages, the order of
-scanning is determined lexically, but the GOROOT tree is always scanned before
-GOPATH.
+The first item in this list matched by the argument is the one whose documentation
+is printed. (See the examples below.) However, if the argument starts with a capital
+letter it is assumed to identify a symbol or method in the current directory.
+
+For packages, the order of scanning is determined lexically in breadth-first order.
+That is, the package presented is the one that matches the search and is nearest
+the root and lexically first at its level of the hierarchy.  The GOROOT tree is
+always scanned in its entirety before GOPATH.
 
 If there is no package specified or matched, the package in the current
 directory is selected, so "go doc Foo" shows the documentation for symbol Foo in
@@ -278,6 +288,14 @@ Examples:
        go doc text/template new # Two arguments
                Show documentation for text/template's New function.
 
+       At least in the current tree, these invocations all print the
+       documentation for json.Decoder's Decode method:
+
+       go doc json.Decoder.Decode
+       go doc json.decoder.decode
+       go doc json.decode
+       cd go/src/encoding/json; go doc decode
+
 Flags:
        -c
                Respect case when matching symbols.
@@ -344,7 +362,7 @@ Generate Go files by processing source
 
 Usage:
 
-       go generate [-run regexp] [file.go... | packages]
+       go generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]
 
 Generate runs commands described by directives within existing
 files. Those commands can run any process but the intent is to
@@ -436,12 +454,14 @@ Go generate accepts one specific flag:
                any trailing spaces and final newline) matches the
                expression.
 
-It also accepts the standard build flags -v, -n, and -x.
+It also accepts the standard build flags including -v, -n, and -x.
 The -v flag prints the names of packages and files as they are
 processed.
 The -n flag prints commands that would be executed.
 The -x flag prints commands as they are executed.
 
+For more about build flags, see 'go help build'.
+
 For more about specifying packages, see 'go help packages'.
 
 
@@ -477,16 +497,22 @@ missing packages but does not use it to look for updates to existing packages.
 
 Get also accepts build flags to control the installation. See 'go help build'.
 
+When checking out a new package, get creates the target directory
+GOPATH/src/<import-path>. If the GOPATH contains multiple entries,
+get uses the first one. See 'go help gopath'.
+
 When checking out or updating a package, get looks for a branch or tag
 that matches the locally installed version of Go. The most important
 rule is that if the local installation is running version "go1", get
 searches for a branch or tag named "go1". If no such version exists it
 retrieves the most recent version of the package.
 
-If the vendoring experiment is enabled (see 'go help gopath'),
-then when go get checks out or updates a Git repository,
+Unless vendoring support is disabled (see 'go help gopath'),
+when go get checks out or updates a Git repository,
 it also updates any git submodules referenced by the repository.
 
+Get never checks out or updates code stored in vendor directories.
+
 For more about specifying packages, see 'go help packages'.
 
 For more about how 'go get' finds source code to
@@ -577,6 +603,14 @@ syntax of package template.  The default output is equivalent to -f
         XTestImports []string // imports from XTestGoFiles
     }
 
+The error information, if any, is
+
+    type PackageError struct {
+        ImportStack   []string // shortest path from package named on command line to this one
+        Pos           string   // position of error (if present, file:line:col)
+        Err           string   // the error itself
+    }
+
 The template function "join" calls strings.Join.
 
 The template function "context" returns the build context, defined as:
@@ -643,7 +677,7 @@ Test packages
 
 Usage:
 
-       go test [-c] [-i] [build and test flags] [packages] [flags for test binary]
+       go test [build/test flags] [packages] [build/test flags & test binary flags]
 
 'Go test' automates testing the packages named by the import paths.
 It prints a summary of the test results in the format:
@@ -673,10 +707,16 @@ non-test installation.
 
 In addition to the build flags, the flags handled by 'go test' itself are:
 
+       -args
+           Pass the remainder of the command line (everything after -args)
+           to the test binary, uninterpreted and unchanged.
+           Because this flag consumes the remainder of the command line,
+           the package list (if present) must appear before this flag.
+
        -c
-               Compile the test binary to pkg.test but do not run it
-               (where pkg is the last element of the package's import path).
-               The file name can be changed with the -o flag.
+           Compile the test binary to pkg.test but do not run it
+           (where pkg is the last element of the package's import path).
+           The file name can be changed with the -o flag.
 
        -exec xprog
            Run the test binary using xprog. The behavior is the same as
@@ -687,17 +727,12 @@ In addition to the build flags, the flags handled by 'go test' itself are:
            Do not run the test.
 
        -o file
-               Compile the test binary to the named file.
-               The test still runs (unless -c or -i is specified).
+           Compile the test binary to the named file.
+           The test still runs (unless -c or -i is specified).
 
 The test binary also accepts flags that control execution of the test; these
 flags are also accessible by 'go test'. See 'go help testflag' for details.
 
-If the test binary needs any other flags, they should be presented after the
-package names. The go tool treats as a flag the first argument that begins with
-a minus sign that it does not recognize itself; that argument and all subsequent
-arguments are passed as arguments to the test binary.
-
 For more about build flags, see 'go help build'.
 For more about specifying packages, see 'go help packages'.
 
@@ -804,6 +839,11 @@ are:
                Build the listed main packages and everything they import into
                executables. Packages not named main are ignored.
 
+       -buildmode=pie
+               Build the listed main packages and everything they import into
+               position independent executables (PIE). Packages not named
+               main are ignored.
+
 
 File types
 
@@ -875,7 +915,7 @@ DIR/bin/quux, not DIR/bin/foo/quux.  The "foo/" prefix is stripped
 so that you can add DIR/bin to your PATH to get at the
 installed commands.  If the GOBIN environment variable is
 set, commands are installed to the directory it names instead
-of DIR/bin.
+of DIR/bin. GOBIN must be an absolute path.
 
 Here's an example directory layout:
 
@@ -933,13 +973,10 @@ See https://golang.org/s/go14internal for details.
 
 Vendor Directories
 
-Go 1.5 includes experimental support for using local copies
-of external dependencies to satisfy imports of those dependencies,
-often referred to as vendoring. Setting the environment variable
-GO15VENDOREXPERIMENT=1 enables that experimental support.
+Go 1.6 includes support for using local copies of external dependencies
+to satisfy imports of those dependencies, often referred to as vendoring.
 
-When the vendor experiment is enabled,
-code below a directory named "vendor" is importable only
+Code below a directory named "vendor" is importable only
 by code in the directory tree rooted at the parent of "vendor",
 and only using an import path that omits the prefix up to and
 including the vendor element.
@@ -977,12 +1014,18 @@ top-level "crash/bang".
 Code in vendor directories is not subject to import path
 checking (see 'go help importpath').
 
-When the vendor experiment is enabled, 'go get' checks out
-submodules when checking out or updating a git repository
-(see 'go help get').
+When 'go get' checks out or updates a git repository, it now also
+updates submodules.
+
+Vendor directories do not affect the placement of new repositories
+being checked out for the first time by 'go get': those are always
+placed in the main GOPATH, never in a vendor subtree.
 
-The vendoring semantics are an experiment, and they may change
-in future releases. Once settled, they will be on by default.
+In Go 1.5, as an experiment, setting the environment variable
+GO15VENDOREXPERIMENT=1 enabled these features.
+As of Go 1.6 they are on by default. To turn them off, set
+GO15VENDOREXPERIMENT=0. In Go 1.7, the environment
+variable will stop having any effect.
 
 See https://golang.org/s/go15vendor for details.
 
@@ -1051,7 +1094,7 @@ Special-purpose environment variables:
                File names in stack traces are rewritten from GOROOT to
                GOROOT_FINAL.
        GO15VENDOREXPERIMENT
-               Set to 1 to enable the Go 1.5 vendoring experiment.
+               Set to 0 to disable vendoring semantics.
        GO_EXTLINK_ENABLED
                Whether the linker should use external linking mode
                when using -linkmode=auto with code that uses cgo.
@@ -1227,10 +1270,10 @@ unless it is being referred to by that import path. In this way, import comments
 let package authors make sure the custom import path is used and not a
 direct path to the underlying code hosting site.
 
-If the vendoring experiment is enabled (see 'go help gopath'),
-then import path checking is disabled for code found within vendor trees.
-This makes it possible to copy code into alternate locations in vendor trees
-without needing to update import comments.
+If vendoring is enabled (see 'go help gopath'), then import path checking is
+disabled for code found within vendor trees. This makes it possible to copy
+code into alternate locations in vendor trees without needing to update import
+comments.
 
 See https://golang.org/s/go14customimport for details.
 
@@ -1286,6 +1329,14 @@ internally at Google all begin with 'google', and paths
 denoting remote repositories begin with the path to the code,
 such as 'github.com/user/repo'.
 
+Packages in a program need not have unique package names,
+but there are two reserved package names with special meaning.
+The name main indicates a command, not a library.
+Commands are built into binaries and cannot be imported.
+The name documentation indicates documentation for
+a non-Go program in the directory. Files in package documentation
+are ignored by the go command.
+
 As a special case, if the package list is a list of .go files from a
 single directory, the command is applied to a single synthesized
 package made up of exactly those files, ignoring any build constraints
@@ -1391,6 +1442,10 @@ control the execution of any test:
            Allow parallel execution of test functions that call t.Parallel.
            The value of this flag is the maximum number of tests to run
            simultaneously; by default, it is set to the value of GOMAXPROCS.
+           Note that -parallel only applies within a single test binary.
+           The 'go test' command may run tests for different packages
+           in parallel as well, according to the setting of the -p flag
+           (see 'go help build').
 
        -run regexp
            Run only those tests and examples matching the regular
@@ -1414,25 +1469,63 @@ control the execution of any test:
            Verbose output: log all tests as they are run. Also print all
            text from Log and Logf calls even if the test succeeds.
 
-The test binary, called pkg.test where pkg is the name of the
-directory containing the package sources, can be invoked directly
-after building it with 'go test -c'. When invoking the test binary
-directly, each of the standard flag names must be prefixed with 'test.',
-as in -test.run=TestMyFunc or -test.v.
+Each of these flags is also recognized with an optional 'test.' prefix,
+as in -test.v. When invoking the generated test binary (the result of
+'go test -c') directly, however, the prefix is mandatory.
+
+The 'go test' command rewrites or removes recognized flags,
+as appropriate, both before and after the optional package list,
+before invoking the test binary.
 
-When running 'go test', flags not listed above are passed through
-unaltered. For instance, the command
+For instance, the command
 
-       go test -x -v -cpuprofile=prof.out -dir=testdata -update
+       go test -v -myflag testdata -cpuprofile=prof.out -x
 
 will compile the test binary and then run it as
 
-       pkg.test -test.v -test.cpuprofile=prof.out -dir=testdata -update
+       pkg.test -test.v -myflag testdata -test.cpuprofile=prof.out
+
+(The -x flag is removed because it applies only to the go command's
+execution, not to the test itself.)
 
 The test flags that generate profiles (other than for coverage) also
 leave the test binary in pkg.test for use when analyzing the profiles.
 
-Flags not recognized by 'go test' must be placed after any specified packages.
+When 'go test' runs a test binary, it does so from within the
+corresponding package's source code directory. Depending on the test,
+it may be necessary to do the same when invoking a generated test
+binary directly.
+
+The command-line package list, if present, must appear before any
+flag not known to the go test command. Continuing the example above,
+the package list would have to appear before -myflag, but could appear
+on either side of -v.
+
+To keep an argument for a test binary from being interpreted as a
+known flag or a package name, use -args (see 'go help test') which
+passes the remainder of the command line through to the test binary
+uninterpreted and unaltered.
+
+For instance, the command
+
+       go test -v -args -x -v
+
+will compile the test binary and then run it as
+
+       pkg.test -test.v -x -v
+
+Similarly,
+
+       go test -args math
+
+will compile the test binary and then run it as
+
+       pkg.test math
+
+In the first example, the -x and the second -v are passed through to the
+test binary unchanged and with no effect on the go command itself.
+In the second example, the argument math is passed through to the test
+binary, instead of being interpreted as the package list.
 
 
 Description of testing functions
index 865871c5314a7e82860c8fa95c2da1c602f6c6d3..3dd9df40282f9f5f9f8dc54fd46130a8b8f3f8d3 100644 (file)
@@ -63,12 +63,16 @@ and test commands:
        -n
                print the commands but do not run them.
        -p n
-               the number of builds that can be run in parallel.
+               the number of programs, such as build commands or
+               test binaries, that can be run in parallel.
                The default is the number of CPUs available, except
                on darwin/arm which defaults to 1.
        -race
                enable data race detection.
                Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
+       -msan
+               enable interoperation with memory sanitizer.
+               Supported only on linux/amd64.
        -v
                print the names of packages as they are compiled.
        -work
@@ -91,13 +95,14 @@ and test commands:
                a suffix to use in the name of the package installation directory,
                in order to keep output separate from default builds.
                If using the -race flag, the install suffix is automatically set to race
-               or, if set explicitly, has _race appended to it.  Using a -buildmode
-               option that requires non-default compile flags has a similar effect.
+               or, if set explicitly, has _race appended to it.  Likewise for the -msan
+               flag.  Using a -buildmode option that requires non-default compile flags
+               has a similar effect.
        -ldflags 'flag list'
                arguments to pass on each go tool link invocation.
        -linkshared
                link against shared libraries previously created with
-               -buildmode=shared
+               -buildmode=shared.
        -pkgdir dir
                install and load all packages from dir instead of the usual locations.
                For example, when building with a non-standard configuration,
@@ -166,6 +171,7 @@ var buildGcflags []string    // -gcflags flag
 var buildLdflags []string    // -ldflags flag
 var buildGccgoflags []string // -gccgoflags flag
 var buildRace bool           // -race flag
+var buildMSan bool           // -msan flag
 var buildToolExec []string   // -toolexec flag
 var buildBuildmode string    // -buildmode flag
 var buildLinkshared bool     // -linkshared flag
@@ -227,6 +233,7 @@ func addBuildFlags(cmd *Command) {
        cmd.Flag.BoolVar(&buildLinkshared, "linkshared", false, "")
        cmd.Flag.StringVar(&buildPkgdir, "pkgdir", "", "")
        cmd.Flag.BoolVar(&buildRace, "race", false, "")
+       cmd.Flag.BoolVar(&buildMSan, "msan", false, "")
        cmd.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "")
        cmd.Flag.Var((*stringsFlag)(&buildToolExec), "toolexec", "")
        cmd.Flag.BoolVar(&buildWork, "work", false, "")
@@ -352,29 +359,46 @@ func buildModeInit() {
                        codegenArg = "-fPIC"
                } else {
                        switch platform {
-                       case "linux/amd64":
+                       case "linux/amd64", "linux/arm", "linux/arm64", "linux/386",
+                               "android/amd64", "android/arm", "android/arm64", "android/386":
                                codegenArg = "-shared"
-                       case "linux/arm":
-                               buildAsmflags = append(buildAsmflags, "-shared")
-                       case "darwin/amd64":
-                       case "android/arm":
+                       case "darwin/amd64", "darwin/386":
                        default:
                                fatalf("-buildmode=c-shared not supported on %s\n", platform)
                        }
                }
                ldBuildmode = "c-shared"
        case "default":
-               ldBuildmode = "exe"
+               switch platform {
+               case "android/arm", "android/arm64", "android/amd64", "android/386":
+                       codegenArg = "-shared"
+                       ldBuildmode = "pie"
+               default:
+                       ldBuildmode = "exe"
+               }
        case "exe":
                pkgsFilter = pkgsMain
                ldBuildmode = "exe"
+       case "pie":
+               if gccgo {
+                       fatalf("-buildmode=pie not supported by gccgo")
+               } else {
+                       switch platform {
+                       case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le",
+                               "android/amd64", "android/arm", "android/arm64", "android/386":
+                               codegenArg = "-shared"
+                       default:
+                               fatalf("-buildmode=pie not supported on %s\n", platform)
+                       }
+               }
+               ldBuildmode = "pie"
        case "shared":
                pkgsFilter = pkgsNotMain
                if gccgo {
                        codegenArg = "-fPIC"
                } else {
                        switch platform {
-                       case "linux/amd64":
+                       case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le":
                        default:
                                fatalf("-buildmode=shared not supported on %s\n", platform)
                        }
@@ -391,9 +415,11 @@ func buildModeInit() {
                if gccgo {
                        codegenArg = "-fPIC"
                } else {
-                       if platform != "linux/amd64" {
-                               fmt.Fprintf(os.Stderr, "go %s: -linkshared is only supported on linux/amd64\n", flag.Args()[0])
-                               os.Exit(2)
+                       switch platform {
+                       case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le":
+                               buildAsmflags = append(buildAsmflags, "-D=GOBUILDMODE_shared=1")
+                       default:
+                               fatalf("-linkshared not supported on %s\n", platform)
                        }
                        codegenArg = "-dynlink"
                        // TODO(mwhudson): remove -w when that gets fixed in linker.
@@ -415,7 +441,7 @@ func buildModeInit() {
 }
 
 func runBuild(cmd *Command, args []string) {
-       raceInit()
+       instrumentInit()
        buildModeInit()
        var b builder
        b.init()
@@ -463,7 +489,12 @@ func runBuild(cmd *Command, args []string) {
 
        var a *action
        if buildBuildmode == "shared" {
-               a = b.libaction(libname(args), pkgsFilter(packages(args)), modeBuild, depMode)
+               pkgs := pkgsFilter(packages(args))
+               if libName, err := libname(args, pkgs); err != nil {
+                       fatalf("%s", err.Error())
+               } else {
+                       a = b.libaction(libName, pkgs, modeBuild, depMode)
+               }
        } else {
                a = &action{}
                for _, p := range pkgsFilter(packages(args)) {
@@ -487,32 +518,73 @@ See also: go build, go get, go clean.
        `,
 }
 
+// isMetaPackage checks if name is a reserved package name that expands to multiple packages
+func isMetaPackage(name string) bool {
+       return name == "std" || name == "cmd" || name == "all"
+}
+
 // libname returns the filename to use for the shared library when using
 // -buildmode=shared.  The rules we use are:
-//  1) Drop any trailing "/..."s if present
-//  2) Change / to -
-//  3) Join arguments with ,
-// So std -> libstd.so
-//    a b/... -> liba,b.so
-//    gopkg.in/tomb.v2 -> libgopkg.in-tomb.v2.so
-func libname(args []string) string {
+// Use arguments for special 'meta' packages:
+//     std --> libstd.so
+//     std cmd --> libstd,cmd.so
+// A single non-meta argument with trailing "/..." is special cased:
+//     foo/... --> libfoo.so
+//     (A relative path like "./..."  expands the "." first)
+// Use import paths for other cases, changing '/' to '-':
+//     somelib --> libsubdir-somelib.so
+//     ./ or ../ --> libsubdir-somelib.so
+//     gopkg.in/tomb.v2 -> libgopkg.in-tomb.v2.so
+//     a/... b/... ---> liba/c,b/d.so - all matching import paths
+// Name parts are joined with ','.
+func libname(args []string, pkgs []*Package) (string, error) {
        var libname string
-       for _, arg := range args {
-               arg = strings.TrimSuffix(arg, "/...")
-               arg = strings.Replace(arg, "/", "-", -1)
+       appendName := func(arg string) {
                if libname == "" {
                        libname = arg
                } else {
                        libname += "," + arg
                }
        }
+       var haveNonMeta bool
+       for _, arg := range args {
+               if isMetaPackage(arg) {
+                       appendName(arg)
+               } else {
+                       haveNonMeta = true
+               }
+       }
+       if len(libname) == 0 { // non-meta packages only. use import paths
+               if len(args) == 1 && strings.HasSuffix(args[0], "/...") {
+                       // Special case of "foo/..." as mentioned above.
+                       arg := strings.TrimSuffix(args[0], "/...")
+                       if build.IsLocalImport(arg) {
+                               cwd, _ := os.Getwd()
+                               bp, _ := buildContext.ImportDir(filepath.Join(cwd, arg), build.FindOnly)
+                               if bp.ImportPath != "" && bp.ImportPath != "." {
+                                       arg = bp.ImportPath
+                               }
+                       }
+                       appendName(strings.Replace(arg, "/", "-", -1))
+               } else {
+                       for _, pkg := range pkgs {
+                               appendName(strings.Replace(pkg.ImportPath, "/", "-", -1))
+                       }
+               }
+       } else if haveNonMeta { // have both meta package and a non-meta one
+               return "", errors.New("mixing of meta and non-meta packages is not allowed")
+       }
        // TODO(mwhudson): Needs to change for platforms that use different naming
        // conventions...
-       return "lib" + libname + ".so"
+       return "lib" + libname + ".so", nil
 }
 
 func runInstall(cmd *Command, args []string) {
-       raceInit()
+       if gobin != "" && !filepath.IsAbs(gobin) {
+               fatalf("cannot install, GOBIN must be an absolute path")
+       }
+
+       instrumentInit()
        buildModeInit()
        pkgs := pkgsFilter(packagesForBuild(args))
 
@@ -537,7 +609,11 @@ func runInstall(cmd *Command, args []string) {
        b.init()
        var a *action
        if buildBuildmode == "shared" {
-               a = b.libaction(libname(args), pkgs, modeInstall, modeInstall)
+               if libName, err := libname(args, pkgs); err != nil {
+                       fatalf("%s", err.Error())
+               } else {
+                       a = b.libaction(libName, pkgs, modeInstall, modeInstall)
+               }
        } else {
                a = &action{}
                var tools []*action
@@ -754,7 +830,9 @@ func goFilesPackage(gofiles []string) *Package {
        pkg := new(Package)
        pkg.local = true
        pkg.cmdline = true
+       stk.push("main")
        pkg.load(&stk, bp, err)
+       stk.pop()
        pkg.localPrefix = dirToImportPath(dir)
        pkg.ImportPath = "command-line-arguments"
        pkg.target = ""
@@ -812,15 +890,17 @@ func readpkglist(shlibpath string) (pkgs []*Package) {
 
 // action returns the action for applying the given operation (mode) to the package.
 // depMode is the action to use when building dependencies.
-// action never looks for p in a shared library.
+// action never looks for p in a shared library, but may find p's dependencies in a
+// shared library if buildLinkshared is true.
 func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action {
-       return b.action1(mode, depMode, p, false)
+       return b.action1(mode, depMode, p, false, "")
 }
 
 // action1 returns the action for applying the given operation (mode) to the package.
 // depMode is the action to use when building dependencies.
 // action1 will look for p in a shared library if lookshared is true.
-func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, lookshared bool) *action {
+// forShlib is the shared library that p will become part of, if any.
+func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, lookshared bool, forShlib string) *action {
        shlib := ""
        if lookshared {
                shlib = p.Shlib
@@ -852,13 +932,23 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
        b.actionCache[key] = a
 
        for _, p1 := range p.imports {
-               ls := buildLinkshared
-               // If p1 is part of the same shared library as p, we need the action
-               // that builds p here, not the shared libary or we get action loops.
-               if p1.Shlib == p.Shlib {
-                       ls = false
+               if forShlib != "" {
+                       // p is part of a shared library.
+                       if p1.Shlib != "" && p1.Shlib != forShlib {
+                               // p1 is explicitly part of a different shared library.
+                               // Put the action for that shared library into a.deps.
+                               a.deps = append(a.deps, b.action1(depMode, depMode, p1, true, p1.Shlib))
+                       } else {
+                               // p1 is (implicitly or not) part of this shared library.
+                               // Put the action for p1 into a.deps.
+                               a.deps = append(a.deps, b.action1(depMode, depMode, p1, false, forShlib))
+                       }
+               } else {
+                       // p is not part of a shared library.
+                       // If p1 is in a shared library, put the action for that into
+                       // a.deps, otherwise put the action for p1 into a.deps.
+                       a.deps = append(a.deps, b.action1(depMode, depMode, p1, buildLinkshared, p1.Shlib))
                }
-               a.deps = append(a.deps, b.action1(depMode, depMode, p1, ls))
        }
 
        // If we are not doing a cross-build, then record the binary we'll
@@ -866,7 +956,7 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
        // using cgo, to make sure we do not overwrite the binary while
        // a package is using it.  If this is a cross-build, then the cgo we
        // are writing is not the cgo we need to use.
-       if goos == runtime.GOOS && goarch == runtime.GOARCH && !buildRace && reqStdPkgSrc {
+       if goos == runtime.GOOS && goarch == runtime.GOARCH && !buildRace && !buildMSan && reqStdPkgSrc {
                if (len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo") && !buildLinkshared && buildBuildmode != "shared" {
                        var stk importStack
                        p1 := loadPackage("cmd/cgo", &stk)
@@ -914,18 +1004,27 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
        switch mode {
        case modeInstall:
                a.f = (*builder).install
-               a.deps = []*action{b.action1(modeBuild, depMode, p, lookshared)}
+               a.deps = []*action{b.action1(modeBuild, depMode, p, lookshared, forShlib)}
                a.target = a.p.target
 
                // Install header for cgo in c-archive and c-shared modes.
                if p.usesCgo() && (buildBuildmode == "c-archive" || buildBuildmode == "c-shared") {
+                       hdrTarget := a.target[:len(a.target)-len(filepath.Ext(a.target))] + ".h"
+                       if buildContext.Compiler == "gccgo" {
+                               // For the header file, remove the "lib"
+                               // added by go/build, so we generate pkg.h
+                               // rather than libpkg.h.
+                               dir, file := filepath.Split(hdrTarget)
+                               file = strings.TrimPrefix(file, "lib")
+                               hdrTarget = filepath.Join(dir, file)
+                       }
                        ah := &action{
                                p:      a.p,
                                deps:   []*action{a.deps[0]},
                                f:      (*builder).installHeader,
                                pkgdir: a.pkgdir,
                                objdir: a.objdir,
-                               target: a.target[:len(a.target)-len(filepath.Ext(a.target))] + ".h",
+                               target: hdrTarget,
                        }
                        a.deps = append(a.deps, ah)
                }
@@ -961,7 +1060,11 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
 
 func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode buildMode) *action {
        a := &action{}
-       if mode == modeBuild {
+       switch mode {
+       default:
+               fatalf("unrecognized mode %v", mode)
+
+       case modeBuild:
                a.f = (*builder).linkShared
                a.target = filepath.Join(b.work, libname)
                for _, p := range pkgs {
@@ -970,14 +1073,15 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
                        }
                        a.deps = append(a.deps, b.action(depMode, depMode, p))
                }
-       } else if mode == modeInstall {
+
+       case modeInstall:
                // Currently build mode shared forces external linking mode, and
-               // external linking mode forces an import of runtime/cgo. So if it
-               // was not passed on the command line and it is not present in
-               // another shared library, add it here.
-               seencgo := false
+               // external linking mode forces an import of runtime/cgo (and
+               // math on arm). So if it was not passed on the command line and
+               // it is not present in another shared library, add it here.
                _, gccgo := buildToolchain.(gccgoToolchain)
                if !gccgo {
+                       seencgo := false
                        for _, p := range pkgs {
                                seencgo = seencgo || (p.Standard && p.ImportPath == "runtime/cgo")
                        }
@@ -997,6 +1101,28 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
                                        pkgs = append(pkgs, p)
                                }
                        }
+                       if goarch == "arm" {
+                               seenmath := false
+                               for _, p := range pkgs {
+                                       seenmath = seenmath || (p.Standard && p.ImportPath == "math")
+                               }
+                               if !seenmath {
+                                       var stk importStack
+                                       p := loadPackage("math", &stk)
+                                       if p.Error != nil {
+                                               fatalf("load math: %v", p.Error)
+                                       }
+                                       computeStale(p)
+                                       // If math is in another shared library, then that's
+                                       // also the shared library that contains runtime, so
+                                       // something will depend on it and so math's staleness
+                                       // will be checked when processing that library.
+                                       if p.Shlib == "" || p.Shlib == libname {
+                                               pkgs = append([]*Package{}, pkgs...)
+                                               pkgs = append(pkgs, p)
+                                       }
+                               }
+                       }
                }
 
                // Figure out where the library will go.
@@ -1029,7 +1155,7 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
                        if err != nil || lstat.ModTime().After(built) {
                                stale = true
                        }
-                       a.deps = append(a.deps, b.action(depMode, depMode, p))
+                       a.deps = append(a.deps, b.action1(depMode, depMode, p, false, a.target))
                }
 
                if stale {
@@ -1047,8 +1173,6 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
                                shlibnameaction.deps = append(shlibnameaction.deps, buildAction)
                        }
                }
-       } else {
-               fatalf("unregonized mode %v", mode)
        }
        return a
 }
@@ -1239,17 +1363,11 @@ func (b *builder) build(a *action) (err error) {
                // different sections of the bootstrap script have to
                // be merged, the banners give patch something
                // to use to find its context.
-               fmt.Printf("\n#\n# %s\n#\n\n", a.p.ImportPath)
+               b.print("\n#\n# " + a.p.ImportPath + "\n#\n\n")
        }
 
        if buildV {
-               fmt.Fprintf(os.Stderr, "%s\n", a.p.ImportPath)
-       }
-
-       if a.p.Standard && a.p.ImportPath == "runtime" && buildContext.Compiler == "gc" &&
-               (!hasString(a.p.GoFiles, "zgoos_"+buildContext.GOOS+".go") ||
-                       !hasString(a.p.GoFiles, "zgoarch_"+buildContext.GOARCH+".go")) {
-               return fmt.Errorf("%s/%s must be bootstrapped using make%v", buildContext.GOOS, buildContext.GOARCH, defaultSuffix())
+               b.print(a.p.ImportPath + "\n")
        }
 
        // Make build directory.
@@ -1393,17 +1511,17 @@ func (b *builder) build(a *action) (err error) {
                switch {
                case strings.HasSuffix(name, _goos_goarch):
                        targ := file[:len(name)-len(_goos_goarch)] + "_GOOS_GOARCH." + ext
-                       if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644, true); err != nil {
+                       if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666, true); err != nil {
                                return err
                        }
                case strings.HasSuffix(name, _goarch):
                        targ := file[:len(name)-len(_goarch)] + "_GOARCH." + ext
-                       if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644, true); err != nil {
+                       if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666, true); err != nil {
                                return err
                        }
                case strings.HasSuffix(name, _goos):
                        targ := file[:len(name)-len(_goos)] + "_GOOS." + ext
-                       if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644, true); err != nil {
+                       if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666, true); err != nil {
                                return err
                        }
                }
@@ -1492,7 +1610,7 @@ func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err e
 
 func (b *builder) installShlibname(a *action) error {
        a1 := a.deps[0]
-       err := ioutil.WriteFile(a.target, []byte(filepath.Base(a1.target)+"\n"), 0644)
+       err := ioutil.WriteFile(a.target, []byte(filepath.Base(a1.target)+"\n"), 0666)
        if err != nil {
                return err
        }
@@ -1516,12 +1634,12 @@ func (b *builder) install(a *action) (err error) {
                }
        }()
        a1 := a.deps[0]
-       perm := os.FileMode(0644)
+       perm := os.FileMode(0666)
        if a1.link {
                switch buildBuildmode {
                case "c-archive", "c-shared":
                default:
-                       perm = 0755
+                       perm = 0777
                }
        }
 
@@ -1595,7 +1713,25 @@ func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode, f
 
        // If we can update the mode and rename to the dst, do it.
        // Otherwise fall back to standard copy.
-       if err := os.Chmod(src, perm); err == nil {
+
+       // The perm argument is meant to be adjusted according to umask,
+       // but we don't know what the umask is.
+       // Create a dummy file to find out.
+       // This avoids build tags and works even on systems like Plan 9
+       // where the file mask computation incorporates other information.
+       mode := perm
+       f, err := os.OpenFile(filepath.Clean(dst)+"-go-tmp-umask", os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm)
+       if err == nil {
+               fi, err := f.Stat()
+               if err == nil {
+                       mode = fi.Mode() & 0777
+               }
+               name := f.Name()
+               f.Close()
+               os.Remove(name)
+       }
+
+       if err := os.Chmod(src, mode); err == nil {
                if err := os.Rename(src, dst); err == nil {
                        if buildX {
                                b.showcmd("", "mv %s %s", src, dst)
@@ -1629,7 +1765,7 @@ func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode, force b
                if fi.IsDir() {
                        return fmt.Errorf("build output %q already exists and is a directory", dst)
                }
-               if !force && !isObject(dst) {
+               if !force && fi.Mode().IsRegular() && !isObject(dst) {
                        return fmt.Errorf("build output %q already exists and is not an object file", dst)
                }
        }
@@ -1641,7 +1777,7 @@ func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode, force b
                }
        }
 
-       os.Remove(dst)
+       mayberemovefile(dst)
        df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
        if err != nil && toolIsWindows {
                // Windows does not allow deletion of a binary file
@@ -1660,7 +1796,7 @@ func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode, force b
        _, err = io.Copy(df, sf)
        df.Close()
        if err != nil {
-               os.Remove(dst)
+               mayberemovefile(dst)
                return fmt.Errorf("copying %s to %s: %v", src, dst, err)
        }
        return nil
@@ -1682,7 +1818,7 @@ func (b *builder) installHeader(a *action) error {
                }
        }
 
-       return b.moveOrCopyFile(a, a.target, src, 0644, true)
+       return b.moveOrCopyFile(a, a.target, src, 0666, true)
 }
 
 // cover runs, in effect,
@@ -1707,6 +1843,7 @@ var objectMagic = [][]byte{
        {0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00},      // PE (Windows) as generated by 6l/8l and gcc
        {0x00, 0x00, 0x01, 0xEB},                  // Plan 9 i386
        {0x00, 0x00, 0x8a, 0x97},                  // Plan 9 amd64
+       {0x00, 0x00, 0x06, 0x47},                  // Plan 9 arm
 }
 
 func isObject(s string) bool {
@@ -1725,6 +1862,16 @@ func isObject(s string) bool {
        return false
 }
 
+// mayberemovefile removes a file only if it is a regular file
+// When running as a user with sufficient privileges, we may delete
+// even device files, for example, which is not intended.
+func mayberemovefile(s string) {
+       if fi, err := os.Lstat(s); err == nil && !fi.Mode().IsRegular() {
+               return
+       }
+       os.Remove(s)
+}
+
 // fmtcmd formats a command in the manner of fmt.Sprintf but also:
 //
 //     If dir is non-empty and the script is not in dir right now,
@@ -2103,7 +2250,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
        if p.Name == "main" {
                gcargs[1] = "main"
        }
-       if p.Standard && p.ImportPath == "runtime" {
+       if p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal")) {
                // runtime compiles with a special gc flag to emit
                // additional reflect type data.
                gcargs = append(gcargs, "-+")
@@ -2208,33 +2355,26 @@ func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s
        for _, f := range ofiles {
                absOfiles = append(absOfiles, mkAbs(objDir, f))
        }
-       cmd := "c"
        absAfile := mkAbs(objDir, afile)
-       appending := false
-       if _, err := os.Stat(absAfile); err == nil {
-               appending = true
-               cmd = "r"
-       }
 
-       cmdline := stringList("pack", cmd, absAfile, absOfiles)
+       // The archive file should have been created by the compiler.
+       // Since it used to not work that way, verify.
+       if _, err := os.Stat(absAfile); err != nil {
+               fatalf("os.Stat of archive file failed: %v", err)
+       }
 
-       if appending {
-               if buildN || buildX {
-                       b.showcmd(p.Dir, "%s # internal", joinUnambiguously(cmdline))
-               }
-               if buildN {
-                       return nil
-               }
-               if err := packInternal(b, absAfile, absOfiles); err != nil {
-                       b.showOutput(p.Dir, p.ImportPath, err.Error()+"\n")
-                       return errPrintedOutput
-               }
+       if buildN || buildX {
+               cmdline := stringList("pack", "r", absAfile, absOfiles)
+               b.showcmd(p.Dir, "%s # internal", joinUnambiguously(cmdline))
+       }
+       if buildN {
                return nil
        }
-
-       // Need actual pack.
-       cmdline[0] = tool("pack")
-       return b.run(p.Dir, p.ImportPath, nil, buildToolExec, cmdline)
+       if err := packInternal(b, absAfile, absOfiles); err != nil {
+               b.showOutput(p.Dir, p.ImportPath, err.Error()+"\n")
+               return errPrintedOutput
+       }
+       return nil
 }
 
 func packInternal(b *builder, afile string, ofiles []string) error {
@@ -2445,11 +2585,11 @@ func (tools gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string
        sfile = mkAbs(p.Dir, sfile)
        defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
        if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
-               defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
+               defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath)
        }
        defs = tools.maybePIC(defs)
        defs = append(defs, b.gccArchArgs()...)
-       return b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-c", "-I", obj, "-o", ofile, defs, sfile)
+       return b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-xassembler-with-cpp", "-I", obj, "-c", "-o", ofile, defs, sfile)
 }
 
 func (gccgoToolchain) pkgpath(basedir string, p *Package) string {
@@ -2464,7 +2604,7 @@ func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles
        for _, f := range ofiles {
                absOfiles = append(absOfiles, mkAbs(objDir, f))
        }
-       return b.run(p.Dir, p.ImportPath, nil, "ar", "cru", mkAbs(objDir, afile), absOfiles)
+       return b.run(p.Dir, p.ImportPath, nil, "ar", "rc", mkAbs(objDir, afile), absOfiles)
 }
 
 func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error {
@@ -2599,6 +2739,10 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
                // libffi.
                ldflags = append(ldflags, "-Wl,-r", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive")
 
+               if b.gccSupportsNoPie() {
+                       ldflags = append(ldflags, "-no-pie")
+               }
+
                // We are creating an object file, so we don't want a build ID.
                ldflags = b.disableBuildID(ldflags)
 
@@ -2606,7 +2750,7 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
                out = out + ".o"
 
        case "c-shared":
-               ldflags = append(ldflags, "-shared", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive", "-lgo", "-lgcc_s", "-lgcc")
+               ldflags = append(ldflags, "-shared", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive", "-lgo", "-lgcc_s", "-lgcc", "-lc", "-lgcc")
 
        default:
                fatalf("-buildmode=%s not supported for gccgo", ldBuildmode)
@@ -2704,43 +2848,6 @@ func gccgoCleanPkgpath(p *Package) string {
        return strings.Map(clean, gccgoPkgpath(p))
 }
 
-// libgcc returns the filename for libgcc, as determined by invoking gcc with
-// the -print-libgcc-file-name option.
-func (b *builder) libgcc(p *Package) (string, error) {
-       var buf bytes.Buffer
-
-       gccCmd := b.gccCmd(p.Dir)
-
-       prev := b.print
-       if buildN {
-               // In -n mode we temporarily swap out the builder's
-               // print function to capture the command-line. This
-               // let's us assign it to $LIBGCC and produce a valid
-               // buildscript for cgo packages.
-               b.print = func(a ...interface{}) (int, error) {
-                       return fmt.Fprint(&buf, a...)
-               }
-       }
-       f, err := b.runOut(p.Dir, p.ImportPath, nil, gccCmd, "-print-libgcc-file-name")
-       if err != nil {
-               return "", fmt.Errorf("gcc -print-libgcc-file-name: %v (%s)", err, f)
-       }
-       if buildN {
-               s := fmt.Sprintf("LIBGCC=$(%s)\n", buf.Next(buf.Len()-1))
-               b.print = prev
-               b.print(s)
-               return "$LIBGCC", nil
-       }
-
-       // The compiler might not be able to find libgcc, and in that case,
-       // it will simply return "libgcc.a", which is of no use to us.
-       if !filepath.IsAbs(string(f)) {
-               return "", nil
-       }
-
-       return strings.Trim(string(f), "\r\n"), nil
-}
-
 // gcc runs the gcc C compiler to create an object from a single C file.
 func (b *builder) gcc(p *Package, out string, flags []string, cfile string) error {
        return b.ccompile(p, out, flags, cfile, b.gccCmd(p.Dir))
@@ -2827,6 +2934,36 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
        return a
 }
 
+// On systems with PIE (position independent executables) enabled by default,
+// -no-pie must be passed when doing a partial link with -Wl,-r. But -no-pie is
+// not supported by all compilers.
+func (b *builder) gccSupportsNoPie() bool {
+       if goos != "linux" {
+               // On some BSD platforms, error messages from the
+               // compiler make it to the console despite cmd.Std*
+               // all being nil. As -no-pie is only required on linux
+               // systems so far, we only test there.
+               return false
+       }
+       src := filepath.Join(b.work, "trivial.c")
+       if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil {
+               return false
+       }
+       cmdArgs := b.gccCmd(b.work)
+       cmdArgs = append(cmdArgs, "-no-pie", "-c", "trivial.c")
+       if buildN || buildX {
+               b.showcmd(b.work, "%s", joinUnambiguously(cmdArgs))
+               if buildN {
+                       return false
+               }
+       }
+       cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
+       cmd.Dir = b.work
+       cmd.Env = envForDir(cmd.Dir, os.Environ())
+       out, err := cmd.CombinedOutput()
+       return err == nil && !bytes.Contains(out, []byte("unrecognized"))
+}
+
 // gccArchArgs returns arguments to pass to gcc based on the architecture.
 func (b *builder) gccArchArgs() []string {
        switch goarch {
@@ -2866,12 +3003,6 @@ func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, ldfl
 
 var cgoRe = regexp.MustCompile(`[/\\:]`)
 
-var (
-       cgoLibGccFile     string
-       cgoLibGccErr      error
-       cgoLibGccFileOnce sync.Once
-)
-
 func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
        cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true)
        _, cgoexeCFLAGS, _, _ := b.cflags(p, false)
@@ -2882,11 +3013,16 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
                cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc")
        }
 
+       if buildMSan && p.ImportPath != "runtime/cgo" {
+               cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...)
+               cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...)
+       }
+
        // Allows including _cgo_export.h from .[ch] files in the package.
        cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", obj)
 
        // cgo
-       // TODO: CGOPKGPATH, CGO_FLAGS?
+       // TODO: CGO_FLAGS?
        gofiles := []string{obj + "_cgo_gotypes.go"}
        cfiles := []string{"_cgo_main.c", "_cgo_export.c"}
        for _, fn := range cgofiles {
@@ -2902,7 +3038,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
        if p.Standard && p.ImportPath == "runtime/cgo" {
                cgoflags = append(cgoflags, "-import_runtime_cgo=false")
        }
-       if p.Standard && (p.ImportPath == "runtime/race" || p.ImportPath == "runtime/cgo") {
+       if p.Standard && (p.ImportPath == "runtime/race" || p.ImportPath == "runtime/msan" || p.ImportPath == "runtime/cgo") {
                cgoflags = append(cgoflags, "-import_syscall=false")
        }
 
@@ -2954,7 +3090,9 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
        var linkobj []string
 
        var bareLDFLAGS []string
-       // filter out -lsomelib, -l somelib, *.{so,dll,dylib}, and (on Darwin) -framework X
+       // When linking relocatable objects, various flags need to be
+       // filtered out as they are inapplicable and can cause some linkers
+       // to fail.
        for i := 0; i < len(cgoLDFLAGS); i++ {
                f := cgoLDFLAGS[i]
                switch {
@@ -2970,7 +3108,6 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
                case strings.HasSuffix(f, ".dylib"),
                        strings.HasSuffix(f, ".so"),
                        strings.HasSuffix(f, ".dll"):
-                       continue
                // Remove any -fsanitize=foo flags.
                // Otherwise the compiler driver thinks that we are doing final link
                // and links sanitizer runtime into the object file. But we are not doing
@@ -2979,27 +3116,27 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
                // See issue 8788 for details.
                case strings.HasPrefix(f, "-fsanitize="):
                        continue
+               // runpath flags not applicable unless building a shared
+               // object or executable; see issue 12115 for details.  This
+               // is necessary as Go currently does not offer a way to
+               // specify the set of LDFLAGS that only apply to shared
+               // objects.
+               case strings.HasPrefix(f, "-Wl,-rpath"):
+                       if f == "-Wl,-rpath" || f == "-Wl,-rpath-link" {
+                               // Skip following argument to -rpath* too.
+                               i++
+                       }
                default:
                        bareLDFLAGS = append(bareLDFLAGS, f)
                }
        }
 
-       cgoLibGccFileOnce.Do(func() {
-               cgoLibGccFile, cgoLibGccErr = b.libgcc(p)
-       })
-       if cgoLibGccFile == "" && cgoLibGccErr != nil {
-               return nil, nil, err
-       }
-
        var staticLibs []string
        if goos == "windows" {
-               // libmingw32 and libmingwex might also use libgcc, so libgcc must come last,
-               // and they also have some inter-dependencies, so must use linker groups.
+               // libmingw32 and libmingwex have some inter-dependencies,
+               // so must use linker groups.
                staticLibs = []string{"-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group"}
        }
-       if cgoLibGccFile != "" {
-               staticLibs = append(staticLibs, cgoLibGccFile)
-       }
 
        cflags := stringList(cgoCPPFLAGS, cgoCFLAGS)
        for _, cfile := range cfiles {
@@ -3045,7 +3182,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
 
        linkobj = append(linkobj, p.SysoFiles...)
        dynobj := obj + "_cgo_.o"
-       pie := goarch == "arm" && (goos == "linux" || goos == "android")
+       pie := (goarch == "arm" && goos == "linux") || goos == "android"
        if pie { // we need to use -pie for Linux/ARM to get accurate imported sym
                cgoLDFLAGS = append(cgoLDFLAGS, "-pie")
        }
@@ -3083,6 +3220,10 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
        }
        ldflags := stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs)
 
+       if b.gccSupportsNoPie() {
+               ldflags = append(ldflags, "-no-pie")
+       }
+
        // We are creating an object file, so we don't want a build ID.
        ldflags = b.disableBuildID(ldflags)
 
@@ -3217,7 +3358,7 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
                return "$INTBITS", nil
        }
        src := filepath.Join(b.work, "swig_intsize.go")
-       if err = ioutil.WriteFile(src, []byte(swigIntSizeCode), 0644); err != nil {
+       if err = ioutil.WriteFile(src, []byte(swigIntSizeCode), 0666); err != nil {
                return
        }
        srcs := []string{src}
@@ -3339,32 +3480,38 @@ func (q *actionQueue) pop() *action {
        return heap.Pop(q).(*action)
 }
 
-func raceInit() {
-       if !buildRace {
+func instrumentInit() {
+       if !buildRace && !buildMSan {
                return
        }
+       if buildRace && buildMSan {
+               fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously", flag.Args()[0])
+               os.Exit(2)
+       }
        if goarch != "amd64" || goos != "linux" && goos != "freebsd" && goos != "darwin" && goos != "windows" {
-               fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
+               fmt.Fprintf(os.Stderr, "go %s: -race and -msan are only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
                os.Exit(2)
        }
-       buildGcflags = append(buildGcflags, "-race")
-       buildLdflags = append(buildLdflags, "-race")
+       if !buildContext.CgoEnabled {
+               fmt.Fprintf(os.Stderr, "go %s: -race requires cgo; enable cgo by setting CGO_ENABLED=1\n", flag.Args()[0])
+               os.Exit(2)
+       }
+       if buildRace {
+               buildGcflags = append(buildGcflags, "-race")
+               buildLdflags = append(buildLdflags, "-race")
+       } else {
+               buildGcflags = append(buildGcflags, "-msan")
+               buildLdflags = append(buildLdflags, "-msan")
+       }
        if buildContext.InstallSuffix != "" {
                buildContext.InstallSuffix += "_"
        }
-       buildContext.InstallSuffix += "race"
-       buildContext.BuildTags = append(buildContext.BuildTags, "race")
-}
 
-// defaultSuffix returns file extension used for command files in
-// current os environment.
-func defaultSuffix() string {
-       switch runtime.GOOS {
-       case "windows":
-               return ".bat"
-       case "plan9":
-               return ".rc"
-       default:
-               return ".bash"
+       if buildRace {
+               buildContext.InstallSuffix += "race"
+               buildContext.BuildTags = append(buildContext.BuildTags, "race")
+       } else {
+               buildContext.InstallSuffix += "msan"
+               buildContext.BuildTags = append(buildContext.BuildTags, "msan")
        }
 }
index b9f42799546e306f8f3762d00d2c6d273d3e50a2..f6992e9e93e478bdd8318f429b57f967c42cd1f6 100644 (file)
@@ -41,9 +41,9 @@ func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
        d.Strict = false
        var t xml.Token
        for {
-               t, err = d.Token()
+               t, err = d.RawToken()
                if err != nil {
-                       if err == io.EOF {
+                       if err == io.EOF || len(imports) > 0 {
                                err = nil
                        }
                        return
index 4a07dfe11f4e76a76a3aa6feceaa55c964ccf367..9b8b8dfc2491b898f7f51987414bdaf5ef93f609 100644 (file)
@@ -32,12 +32,17 @@ which is schematically one of these:
 
        go doc <pkg>
        go doc <sym>[.<method>]
-       go doc [<pkg>].<sym>[.<method>]
+       go doc [<pkg>.]<sym>[.<method>]
+       go doc [<pkg>.][<sym>.]<method>
 
-The first item in this list matched by the argument is the one whose
-documentation is printed. (See the examples below.) For packages, the order of
-scanning is determined lexically, but the GOROOT tree is always scanned before
-GOPATH.
+The first item in this list matched by the argument is the one whose documentation
+is printed. (See the examples below.) However, if the argument starts with a capital
+letter it is assumed to identify a symbol or method in the current directory.
+
+For packages, the order of scanning is determined lexically in breadth-first order.
+That is, the package presented is the one that matches the search and is nearest
+the root and lexically first at its level of the hierarchy.  The GOROOT tree is
+always scanned in its entirety before GOPATH.
 
 If there is no package specified or matched, the package in the current
 directory is selected, so "go doc Foo" shows the documentation for symbol Foo in
@@ -85,6 +90,14 @@ Examples:
        go doc text/template new # Two arguments
                Show documentation for text/template's New function.
 
+       At least in the current tree, these invocations all print the
+       documentation for json.Decoder's Decode method:
+
+       go doc json.Decoder.Decode
+       go doc json.decoder.decode
+       go doc json.decode
+       cd go/src/encoding/json; go doc decode
+
 Flags:
        -c
                Respect case when matching symbols.
index 600accac03f2767bf086d45b8a94ec5313d8d123..24f612756b64e02ab828f10004a10dabbad9c784 100644 (file)
@@ -33,6 +33,11 @@ func mkEnv() []envVar {
        var b builder
        b.init()
 
+       vendorExpValue := "0"
+       if go15VendorExperiment {
+               vendorExpValue = "1"
+       }
+
        env := []envVar{
                {"GOARCH", goarch},
                {"GOBIN", gobin},
@@ -44,7 +49,7 @@ func mkEnv() []envVar {
                {"GORACE", os.Getenv("GORACE")},
                {"GOROOT", goroot},
                {"GOTOOLDIR", toolDir},
-               {"GO15VENDOREXPERIMENT", os.Getenv("GO15VENDOREXPERIMENT")},
+               {"GO15VENDOREXPERIMENT", vendorExpValue},
 
                // disable escape codes in clang errors
                {"TERM", "dumb"},
index efdc229b2281a2e0463e12d4308c85299ed56c74..cb54018bab52d7709b8a140d2aee5e38a2d61ced 100644 (file)
@@ -22,7 +22,7 @@ import (
 
 var cmdGenerate = &Command{
        Run:       runGenerate,
-       UsageLine: "generate [-run regexp] [file.go... | packages]",
+       UsageLine: "generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]",
        Short:     "generate Go files by processing source",
        Long: `
 Generate runs commands described by directives within existing
@@ -115,12 +115,14 @@ Go generate accepts one specific flag:
                any trailing spaces and final newline) matches the
                expression.
 
-It also accepts the standard build flags -v, -n, and -x.
+It also accepts the standard build flags including -v, -n, and -x.
 The -v flag prints the names of packages and files as they are
 processed.
 The -n flag prints commands that would be executed.
 The -x flag prints commands as they are executed.
 
+For more about build flags, see 'go help build'.
+
 For more about specifying packages, see 'go help packages'.
        `,
 }
@@ -179,6 +181,7 @@ type Generator struct {
        pkg      string
        commands map[string][]string
        lineNum  int // current line number.
+       env      []string
 }
 
 // run runs the generators in the current file.
@@ -242,6 +245,7 @@ func (g *Generator) run() (ok bool) {
                        }
                }
 
+               g.setEnv()
                words := g.split(string(buf))
                if len(words) == 0 {
                        g.errorf("no arguments to directive")
@@ -269,6 +273,19 @@ func isGoGenerate(buf []byte) bool {
        return bytes.HasPrefix(buf, []byte("//go:generate ")) || bytes.HasPrefix(buf, []byte("//go:generate\t"))
 }
 
+// setEnv sets the extra environment variables used when executing a
+// single go:generate command.
+func (g *Generator) setEnv() {
+       g.env = []string{
+               "GOARCH=" + runtime.GOARCH,
+               "GOOS=" + runtime.GOOS,
+               "GOFILE=" + g.file,
+               "GOLINE=" + strconv.Itoa(g.lineNum),
+               "GOPACKAGE=" + g.pkg,
+               "DOLLAR=" + "$",
+       }
+}
+
 // split breaks the line into words, evaluating quoted
 // strings and evaluating environment variables.
 // The initial //go:generate element is present in line.
@@ -345,22 +362,13 @@ func (g *Generator) errorf(format string, args ...interface{}) {
 // expandVar expands the $XXX invocation in word. It is called
 // by os.Expand.
 func (g *Generator) expandVar(word string) string {
-       switch word {
-       case "GOARCH":
-               return buildContext.GOARCH
-       case "GOOS":
-               return buildContext.GOOS
-       case "GOFILE":
-               return g.file
-       case "GOLINE":
-               return fmt.Sprint(g.lineNum)
-       case "GOPACKAGE":
-               return g.pkg
-       case "DOLLAR":
-               return "$"
-       default:
-               return os.Getenv(word)
+       w := word + "="
+       for _, e := range g.env {
+               if strings.HasPrefix(e, w) {
+                       return e[len(w):]
+               }
        }
+       return os.Getenv(word)
 }
 
 // identLength returns the length of the identifier beginning the string.
@@ -396,13 +404,7 @@ func (g *Generator) exec(words []string) {
        cmd.Stderr = os.Stderr
        // Run the command in the package directory.
        cmd.Dir = g.dir
-       env := []string{
-               "GOARCH=" + runtime.GOARCH,
-               "GOOS=" + runtime.GOOS,
-               "GOFILE=" + g.file,
-               "GOPACKAGE=" + g.pkg,
-       }
-       cmd.Env = mergeEnvLists(env, origEnv)
+       cmd.Env = mergeEnvLists(g.env, origEnv)
        err := cmd.Run()
        if err != nil {
                g.errorf("running %q: %s", words[0], err)
index 169d71ca812b7515e12a3c5909f21dce38b9cf02..ba0669278e7af6e2d4da5227017822dfc8ac1dbe 100644 (file)
@@ -39,6 +39,7 @@ func TestGenerateCommandParse(t *testing.T) {
                pkg:      "sys",
                commands: make(map[string][]string),
        }
+       g.setEnv()
        g.setShorthand([]string{"-command", "yacc", "go", "tool", "yacc"})
        for _, test := range splitTests {
                // First with newlines.
index e95201a69307b040de55a24082c37701c20b6a40..a298049a9d21de2b498a3f6fa801fae8e1b4bf38 100644 (file)
@@ -45,16 +45,22 @@ missing packages but does not use it to look for updates to existing packages.
 
 Get also accepts build flags to control the installation. See 'go help build'.
 
+When checking out a new package, get creates the target directory 
+GOPATH/src/<import-path>. If the GOPATH contains multiple entries,
+get uses the first one. See 'go help gopath'.
+
 When checking out or updating a package, get looks for a branch or tag
 that matches the locally installed version of Go. The most important
 rule is that if the local installation is running version "go1", get
 searches for a branch or tag named "go1". If no such version exists it
 retrieves the most recent version of the package.
 
-If the vendoring experiment is enabled (see 'go help gopath'),
-then when go get checks out or updates a Git repository,
+Unless vendoring support is disabled (see 'go help gopath'),
+when go get checks out or updates a Git repository,
 it also updates any git submodules referenced by the repository.
 
+Get never checks out or updates code stored in vendor directories.
+
 For more about specifying packages, see 'go help packages'.
 
 For more about how 'go get' finds source code to
@@ -84,8 +90,12 @@ func runGet(cmd *Command, args []string) {
        // Disable any prompting for passwords by Git.
        // Only has an effect for 2.3.0 or later, but avoiding
        // the prompt in earlier versions is just too hard.
-       // See golang.org/issue/9341.
-       os.Setenv("GIT_TERMINAL_PROMPT", "0")
+       // If user has explicitly set GIT_TERMINAL_PROMPT=1, keep
+       // prompting.
+       // See golang.org/issue/9341 and golang.org/issue/12706.
+       if os.Getenv("GIT_TERMINAL_PROMPT") == "" {
+               os.Setenv("GIT_TERMINAL_PROMPT", "0")
+       }
 
        // Phase 1.  Download/update.
        var stk importStack
index 77b2628982bb81675d07d2705017aa1dd7c1efe4..a901ca8666cfcf5a6ea7ade308309588a1a949a1 100644 (file)
@@ -31,8 +31,7 @@ var (
 
        exeSuffix string // ".exe" on Windows
 
-       builder             = testenv.Builder()
-       skipExternalBuilder = false // skip external tests on this builder
+       skipExternal = false // skip external tests
 )
 
 func init() {
@@ -44,14 +43,21 @@ func init() {
                case "arm", "arm64":
                        canRun = false
                }
-       }
-
-       if strings.HasPrefix(builder+"-", "freebsd-arm-") {
-               skipExternalBuilder = true
-               canRun = false
-       }
-
-       switch runtime.GOOS {
+       case "linux":
+               switch runtime.GOARCH {
+               case "arm":
+                       // many linux/arm machines are too slow to run
+                       // the full set of external tests.
+                       skipExternal = true
+               }
+       case "freebsd":
+               switch runtime.GOARCH {
+               case "arm":
+                       // many freebsd/arm machines are too slow to run
+                       // the full set of external tests.
+                       skipExternal = true
+                       canRun = false
+               }
        case "windows":
                exeSuffix = ".exe"
        }
@@ -83,8 +89,6 @@ func TestMain(m *testing.M) {
                case "linux", "darwin", "freebsd", "windows":
                        canRace = canCgo && runtime.GOARCH == "amd64"
                }
-
-               measureTick("./testgo" + exeSuffix)
        }
 
        // Don't let these environment variables confuse the test.
@@ -103,24 +107,8 @@ func TestMain(m *testing.M) {
 // The length of an mtime tick on this system.  This is an estimate of
 // how long we need to sleep to ensure that the mtime of two files is
 // different.
-var mtimeTick time.Duration
-
-// measureTick sets mtimeTick by looking at the rounding of the mtime
-// of a file.
-func measureTick(path string) {
-       st, err := os.Stat(path)
-       if err != nil {
-               // Default to one second, the most conservative value.
-               mtimeTick = time.Second
-               return
-       }
-       mtime := st.ModTime()
-       t := time.Microsecond
-       for mtime.Round(t).Equal(mtime) && t < time.Second {
-               t *= 10
-       }
-       mtimeTick = t
-}
+// We used to try to be clever but that didn't always work (see golang.org/issue/12205).
+var mtimeTick time.Duration = 1 * time.Second
 
 // Manage a single run of the testgo binary.
 type testgoData struct {
@@ -138,8 +126,8 @@ type testgoData struct {
 func testgo(t *testing.T) *testgoData {
        testenv.MustHaveGoBuild(t)
 
-       if skipExternalBuilder {
-               t.Skip("skipping external tests on %s builder", builder)
+       if skipExternal {
+               t.Skip("skipping external tests on %s/%s", runtime.GOOS, runtime.GOARCH)
        }
 
        return &testgoData{t: t}
@@ -452,7 +440,7 @@ func (tg *testgoData) grepCountBoth(match string) int {
 // removed if it exists.
 func (tg *testgoData) creatingTemp(path string) {
        if filepath.IsAbs(path) && !strings.HasPrefix(path, tg.tempdir) {
-               tg.t.Fatal("internal testsuite error: creatingTemp(%q) with absolute path not in temporary directory", path)
+               tg.t.Fatalf("internal testsuite error: creatingTemp(%q) with absolute path not in temporary directory", path)
        }
        // If we have changed the working directory, make sure we have
        // an absolute path, because we are going to change directory
@@ -671,17 +659,48 @@ func TestGoBuildDashAInDevBranch(t *testing.T) {
        tg.grepStderr("runtime", "testgo build -a math in dev branch DID NOT build runtime, but should have")
 }
 
-func TestGoBuilDashAInReleaseBranch(t *testing.T) {
+func TestGoBuildDashAInReleaseBranch(t *testing.T) {
        if testing.Short() {
                t.Skip("don't rebuild the standard library in short mode")
        }
 
        tg := testgo(t)
        defer tg.cleanup()
-       tg.run("install", "math") // should be up to date already but just in case
+       tg.run("install", "math", "net/http") // should be up to date already but just in case
        tg.setenv("TESTGO_IS_GO_RELEASE", "1")
-       tg.run("build", "-v", "-a", "math")
-       tg.grepStderr("runtime", "testgo build -a math in dev branch did not build runtime, but should have")
+       tg.run("install", "-v", "-a", "math")
+       tg.grepStderr("runtime", "testgo build -a math in release branch DID NOT build runtime, but should have")
+
+       // Now runtime.a is updated (newer mtime), so everything would look stale if not for being a release.
+       //
+       tg.run("build", "-v", "net/http")
+       tg.grepStderrNot("strconv", "testgo build -v net/http in release branch with newer runtime.a DID build strconv but should not have")
+       tg.grepStderrNot("golang.org/x/net/http2/hpack", "testgo build -v net/http in release branch with newer runtime.a DID build .../golang.org/x/net/http2/hpack but should not have")
+       tg.grepStderrNot("net/http", "testgo build -v net/http in release branch with newer runtime.a DID build net/http but should not have")
+}
+
+func TestGoListStandard(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.cd(runtime.GOROOT() + "/src")
+       tg.run("list", "-f", "{{if not .Standard}}{{.ImportPath}}{{end}}", "./...")
+       stdout := tg.getStdout()
+       for _, line := range strings.Split(stdout, "\n") {
+               if strings.HasPrefix(line, "_/") && strings.HasSuffix(line, "/src") {
+                       // $GOROOT/src shows up if there are any .go files there.
+                       // We don't care.
+                       continue
+               }
+               if line == "" {
+                       continue
+               }
+               t.Errorf("package in GOROOT not listed as standard: %v", line)
+       }
+
+       // Similarly, expanding std should include some of our vendored code.
+       tg.run("list", "std", "cmd")
+       tg.grepStdout("golang.org/x/net/http2/hpack", "list std cmd did not mention vendored hpack")
+       tg.grepStdout("golang.org/x/arch/x86/x86asm", "list std cmd did not mention vendored x86asm")
 }
 
 func TestGoInstallCleansUpAfterGoBuild(t *testing.T) {
@@ -775,6 +794,28 @@ func TestGoInstallDetectsRemovedFiles(t *testing.T) {
        tg.wantStale("mypkg", "./testgo list mypkg claims mypkg is NOT stale after removing y.go; should be stale")
 }
 
+func TestWildcardMatchesSyntaxErrorDirs(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.tempFile("src/mypkg/x.go", `package mypkg`)
+       tg.tempFile("src/mypkg/y.go", `pkg mypackage`)
+       tg.setenv("GOPATH", tg.path("."))
+       tg.cd(tg.path("src/mypkg"))
+       tg.runFail("list", "./...")
+       tg.runFail("build", "./...")
+       tg.runFail("install", "./...")
+}
+
+func TestGoListWithTags(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.tempFile("src/mypkg/x.go", "// +build thetag\n\npackage mypkg\n")
+       tg.setenv("GOPATH", tg.path("."))
+       tg.cd(tg.path("./src"))
+       tg.run("list", "-tags=thetag", "./my...")
+       tg.grepStdout("mypkg", "did not find mypkg")
+}
+
 func TestGoInstallErrorOnCrossCompileToBin(t *testing.T) {
        if testing.Short() {
                t.Skip("don't install into GOROOT in short mode")
@@ -951,6 +992,16 @@ func TestInternalPackagesOutsideGOROOTAreRespected(t *testing.T) {
        tg.grepBoth("use of internal package not allowed", "wrote error message for testdata/testinternal2")
 }
 
+func TestRunInternal(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       dir := filepath.Join(tg.pwd(), "testdata")
+       tg.setenv("GOPATH", dir)
+       tg.run("run", filepath.Join(dir, "src/run/good.go"))
+       tg.runFail("run", filepath.Join(dir, "src/run/bad.go"))
+       tg.grepStderr("use of internal package not allowed", "unexpected error for run/bad.go")
+}
+
 func testMove(t *testing.T, vcs, url, base, config string) {
        testenv.MustHaveExternalNetwork(t)
 
@@ -1053,7 +1104,6 @@ func TestImportCommentConflict(t *testing.T) {
 // cmd/go: custom import path checking should not apply to github.com/xxx/yyy.
 func TestIssue10952(t *testing.T) {
        testenv.MustHaveExternalNetwork(t)
-
        if _, err := exec.LookPath("git"); err != nil {
                t.Skip("skipping because git binary not found")
        }
@@ -1071,6 +1121,34 @@ func TestIssue10952(t *testing.T) {
        tg.run("get", "-d", "-u", importPath)
 }
 
+func TestGetGitDefaultBranch(t *testing.T) {
+       testenv.MustHaveExternalNetwork(t)
+       if _, err := exec.LookPath("git"); err != nil {
+               t.Skip("skipping because git binary not found")
+       }
+
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.parallel()
+       tg.tempDir("src")
+       tg.setenv("GOPATH", tg.path("."))
+
+       // This repo has two branches, master and another-branch.
+       // The another-branch is the default that you get from 'git clone'.
+       // The go get command variants should not override this.
+       const importPath = "github.com/rsc/go-get-default-branch"
+
+       tg.run("get", "-d", importPath)
+       repoDir := tg.path("src/" + importPath)
+       defer tg.resetReadOnlyFlagAll(repoDir)
+       tg.runGit(repoDir, "branch", "--contains", "HEAD")
+       tg.grepStdout(`\* another-branch`, "not on correct default branch")
+
+       tg.run("get", "-d", "-u", importPath)
+       tg.runGit(repoDir, "branch", "--contains", "HEAD")
+       tg.grepStdout(`\* another-branch`, "not on correct default branch")
+}
+
 func TestDisallowedCSourceFiles(t *testing.T) {
        tg := testgo(t)
        defer tg.cleanup()
@@ -1139,6 +1217,15 @@ func TestInstallFailsWithNoBuildableFiles(t *testing.T) {
        tg.grepStderr("no buildable Go source files", "go install cgotest did not report 'no buildable Go Source files'")
 }
 
+func TestRelativeGOBINFail(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.tempFile("triv.go", `package main; func main() {}`)
+       tg.setenv("GOBIN", ".")
+       tg.runFail("install")
+       tg.grepStderr("cannot install, GOBIN must be an absolute path", "go install must fail if $GOBIN is a relative path")
+}
+
 // Test that without $GOBIN set, binaries get installed
 // into the GOPATH bin directory.
 func TestInstallIntoGOPATH(t *testing.T) {
@@ -1150,9 +1237,21 @@ func TestInstallIntoGOPATH(t *testing.T) {
        tg.wantExecutable("testdata/bin/go-cmd-test"+exeSuffix, "go install go-cmd-test did not write to testdata/bin/go-cmd-test")
 }
 
+// Issue 12407
+func TestBuildOutputToDevNull(t *testing.T) {
+       if runtime.GOOS == "plan9" {
+               t.Skip("skipping because /dev/null is a regular file on plan9")
+       }
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+       tg.run("build", "-o", os.DevNull, "go-cmd-test")
+}
+
 func TestPackageMainTestImportsArchiveNotBinary(t *testing.T) {
        tg := testgo(t)
        defer tg.cleanup()
+       tg.parallel()
        gobin := filepath.Join(tg.pwd(), "testdata", "bin")
        tg.creatingTemp(gobin)
        tg.setenv("GOBIN", gobin)
@@ -1165,6 +1264,17 @@ func TestPackageMainTestImportsArchiveNotBinary(t *testing.T) {
        tg.run("test", "main_test")
 }
 
+// Issue 12690
+func TestPackageNotStaleWithTrailingSlash(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       goroot := runtime.GOROOT()
+       tg.setenv("GOROOT", goroot+"/")
+       tg.wantNotStale("runtime", "with trailing slash in GOROOT, runtime listed as stale")
+       tg.wantNotStale("os", "with trailing slash in GOROOT, os listed as stale")
+       tg.wantNotStale("io", "with trailing slash in GOROOT, io listed as stale")
+}
+
 // With $GOBIN set, binaries get installed to $GOBIN.
 func TestInstallIntoGOBIN(t *testing.T) {
        tg := testgo(t)
@@ -1357,6 +1467,18 @@ func TestGoListCmdOnlyShowsCommands(t *testing.T) {
        }
 }
 
+func TestGoListDedupsPackages(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+       tg.run("list", "xtestonly", "./testdata/src/xtestonly/...")
+       got := strings.TrimSpace(tg.getStdout())
+       const want = "xtestonly"
+       if got != want {
+               t.Errorf("got %q; want %q", got, want)
+       }
+}
+
 // Issue 4096. Validate the output of unsuccessful go install foo/quxx.
 func TestUnsuccessfulGoInstallShouldMentionMissingPackage(t *testing.T) {
        tg := testgo(t)
@@ -1833,6 +1955,9 @@ func TestIssue6480(t *testing.T) {
 
 // cmd/cgo: undefined reference when linking a C-library using gccgo
 func TestIssue7573(t *testing.T) {
+       if !canCgo {
+               t.Skip("skipping because cgo not enabled")
+       }
        if _, err := exec.LookPath("gccgo"); err != nil {
                t.Skip("skipping because no gccgo compiler found")
        }
@@ -1931,6 +2056,13 @@ func TestGoTestFooTestWorks(t *testing.T) {
        tg.run("test", "testdata/standalone_test.go")
 }
 
+func TestGoTestFlagsAfterPackage(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.run("test", "testdata/flag_test.go", "-v", "-args", "-v=7") // Two distinct -v flags.
+       tg.run("test", "-v", "testdata/flag_test.go", "-args", "-v=7") // Two distinct -v flags.
+}
+
 func TestGoTestXtestonlyWorks(t *testing.T) {
        tg := testgo(t)
        defer tg.cleanup()
@@ -1991,6 +2123,21 @@ func TestGoGenerateRunFlag(t *testing.T) {
        tg.grepStdoutNot("no", "go generate -run yes ./testdata/generate/test4.go selected no")
 }
 
+func TestGoGenerateEnv(t *testing.T) {
+       switch runtime.GOOS {
+       case "plan9", "windows":
+               t.Skipf("skipping because %s does not have the env command", runtime.GOOS)
+       }
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.parallel()
+       tg.tempFile("env.go", "package main\n\n//go:generate env")
+       tg.run("generate", tg.path("env.go"))
+       for _, v := range []string{"GOARCH", "GOOS", "GOFILE", "GOLINE", "GOPACKAGE", "DOLLAR"} {
+               tg.grepStdout("^"+v+"=", "go generate environment missing "+v)
+       }
+}
+
 func TestGoGetCustomDomainWildcard(t *testing.T) {
        testenv.MustHaveExternalNetwork(t)
 
@@ -2051,6 +2198,17 @@ func TestGoGetRscIoToolstash(t *testing.T) {
        tg.run("get", "./toolstash")
 }
 
+// Issue 13037: Was not parsing <meta> tags in 404 served over HTTPS
+func TestGoGetHTTPS404(t *testing.T) {
+       testenv.MustHaveExternalNetwork(t)
+
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.tempDir("src")
+       tg.setenv("GOPATH", tg.path("."))
+       tg.run("get", "bazil.org/fuse/fs/fstestutil")
+}
+
 // Test that you can not import a main package.
 func TestIssue4210(t *testing.T) {
        tg := testgo(t)
@@ -2128,7 +2286,11 @@ func TestGoGetInsecureCustomDomain(t *testing.T) {
 }
 
 func TestIssue10193(t *testing.T) {
+       t.Skip("depends on code.google.com")
        testenv.MustHaveExternalNetwork(t)
+       if _, err := exec.LookPath("hg"); err != nil {
+               t.Skip("skipping because hg binary not found")
+       }
 
        tg := testgo(t)
        defer tg.cleanup()
@@ -2199,7 +2361,7 @@ func TestGoTestImportErrorStack(t *testing.T) {
        tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
        tg.runFail("test", "testdep/p1")
        if !strings.Contains(tg.stderr.String(), out) {
-               t.Fatal("did not give full import stack:\n\n%s", tg.stderr.String())
+               t.Fatalf("did not give full import stack:\n\n%s", tg.stderr.String())
        }
 }
 
@@ -2387,3 +2549,12 @@ func TestGoBuildARM(t *testing.T) {
        tg.run("build", "hello.go")
        tg.grepStderrNot("unable to find math.a", "did not build math.a correctly")
 }
+
+func TestIssue13655(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       for _, pkg := range []string{"runtime", "runtime/internal/atomic"} {
+               tg.run("list", "-f", "{{.Deps}}", pkg)
+               tg.grepStdout("runtime/internal/sys", "did not find required dependency of "+pkg+" on runtime/internal/sys")
+       }
+}
diff --git a/libgo/go/cmd/go/go_unix_test.go b/libgo/go/cmd/go/go_unix_test.go
new file mode 100644 (file)
index 0000000..0d85859
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2015 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package main_test
+
+import (
+       "os"
+       "syscall"
+       "testing"
+)
+
+func TestGoBuildUmask(t *testing.T) {
+       // Do not use tg.parallel; avoid other tests seeing umask manipulation.
+       mask := syscall.Umask(0077) // prohibit low bits
+       defer syscall.Umask(mask)
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.tempFile("x.go", `package main; func main() {}`)
+       tg.creatingTemp("x")
+       tg.run("build", tg.path("x.go"))
+       fi, err := os.Stat("x")
+       if err != nil {
+               t.Fatal(err)
+       }
+       if mode := fi.Mode(); mode&0077 != 0 {
+               t.Fatalf("wrote x with mode=%v, wanted no 0077 bits", mode)
+       }
+}
index 5dff2670f1b990471dee5a4338fee5e3ee9ab6a8..d8e7efedb3750b67e51d130a77c6a28195816546 100644 (file)
@@ -79,6 +79,14 @@ internally at Google all begin with 'google', and paths
 denoting remote repositories begin with the path to the code,
 such as 'github.com/user/repo'.
 
+Packages in a program need not have unique package names,
+but there are two reserved package names with special meaning.
+The name main indicates a command, not a library.
+Commands are built into binaries and cannot be imported.
+The name documentation indicates documentation for
+a non-Go program in the directory. Files in package documentation
+are ignored by the go command.
+
 As a special case, if the package list is a list of .go files from a
 single directory, the command is applied to a single synthesized
 package made up of exactly those files, ignoring any build constraints
@@ -261,10 +269,10 @@ unless it is being referred to by that import path. In this way, import comments
 let package authors make sure the custom import path is used and not a
 direct path to the underlying code hosting site.
 
-If the vendoring experiment is enabled (see 'go help gopath'),
-then import path checking is disabled for code found within vendor trees.
-This makes it possible to copy code into alternate locations in vendor trees
-without needing to update import comments.
+If vendoring is enabled (see 'go help gopath'), then import path checking is
+disabled for code found within vendor trees. This makes it possible to copy
+code into alternate locations in vendor trees without needing to update import
+comments.
 
 See https://golang.org/s/go14customimport for details.
        `,
@@ -307,7 +315,7 @@ DIR/bin/quux, not DIR/bin/foo/quux.  The "foo/" prefix is stripped
 so that you can add DIR/bin to your PATH to get at the
 installed commands.  If the GOBIN environment variable is
 set, commands are installed to the directory it names instead
-of DIR/bin.
+of DIR/bin. GOBIN must be an absolute path.
 
 Here's an example directory layout:
 
@@ -365,13 +373,10 @@ See https://golang.org/s/go14internal for details.
 
 Vendor Directories
 
-Go 1.5 includes experimental support for using local copies
-of external dependencies to satisfy imports of those dependencies,
-often referred to as vendoring. Setting the environment variable
-GO15VENDOREXPERIMENT=1 enables that experimental support.
+Go 1.6 includes support for using local copies of external dependencies
+to satisfy imports of those dependencies, often referred to as vendoring.
 
-When the vendor experiment is enabled,
-code below a directory named "vendor" is importable only
+Code below a directory named "vendor" is importable only
 by code in the directory tree rooted at the parent of "vendor",
 and only using an import path that omits the prefix up to and
 including the vendor element.
@@ -409,12 +414,18 @@ top-level "crash/bang".
 Code in vendor directories is not subject to import path
 checking (see 'go help importpath').
 
-When the vendor experiment is enabled, 'go get' checks out
-submodules when checking out or updating a git repository
-(see 'go help get').
+When 'go get' checks out or updates a git repository, it now also
+updates submodules.
+
+Vendor directories do not affect the placement of new repositories
+being checked out for the first time by 'go get': those are always
+placed in the main GOPATH, never in a vendor subtree.
 
-The vendoring semantics are an experiment, and they may change
-in future releases. Once settled, they will be on by default.
+In Go 1.5, as an experiment, setting the environment variable
+GO15VENDOREXPERIMENT=1 enabled these features.
+As of Go 1.6 they are on by default. To turn them off, set
+GO15VENDOREXPERIMENT=0. In Go 1.7, the environment
+variable will stop having any effect.
 
 See https://golang.org/s/go15vendor for details.
        `,
@@ -487,7 +498,7 @@ Special-purpose environment variables:
                File names in stack traces are rewritten from GOROOT to
                GOROOT_FINAL.
        GO15VENDOREXPERIMENT
-               Set to 1 to enable the Go 1.5 vendoring experiment.
+               Set to 0 to disable vendoring semantics.
        GO_EXTLINK_ENABLED
                Whether the linker should use external linking mode
                when using -linkmode=auto with code that uses cgo.
@@ -570,5 +581,10 @@ are:
        -buildmode=exe
                Build the listed main packages and everything they import into
                executables. Packages not named main are ignored.
+
+       -buildmode=pie
+               Build the listed main packages and everything they import into
+               position independent executables (PIE). Packages not named
+               main are ignored.
 `,
 }
index 7979c41b11bae8a59a68eb23d1f184009fd0aa4f..3a6f19db8482ca2e3ead6e10d0e927b2fd64cd5c 100644 (file)
@@ -12,6 +12,7 @@
 package main
 
 import (
+       "crypto/tls"
        "fmt"
        "io"
        "io/ioutil"
@@ -24,8 +25,17 @@ import (
 // httpClient is the default HTTP client, but a variable so it can be
 // changed by tests, without modifying http.DefaultClient.
 var httpClient = http.DefaultClient
-var impatientHTTPClient = &http.Client{
+
+// impatientInsecureHTTPClient is used in -insecure mode,
+// when we're connecting to https servers that might not be there
+// or might be using self-signed certificates.
+var impatientInsecureHTTPClient = &http.Client{
        Timeout: time.Duration(5 * time.Second),
+       Transport: &http.Transport{
+               TLSClientConfig: &tls.Config{
+                       InsecureSkipVerify: true,
+               },
+       },
 }
 
 type httpError struct {
@@ -71,7 +81,7 @@ func httpsOrHTTP(importPath string, security securityMode) (urlStr string, body
                        log.Printf("Fetching %s", urlStr)
                }
                if security == insecure && scheme == "https" { // fail earlier
-                       res, err = impatientHTTPClient.Get(urlStr)
+                       res, err = impatientInsecureHTTPClient.Get(urlStr)
                } else {
                        res, err = httpClient.Get(urlStr)
                }
@@ -83,16 +93,12 @@ func httpsOrHTTP(importPath string, security securityMode) (urlStr string, body
                }
        }
        urlStr, res, err := fetch("https")
-       if err != nil || res.StatusCode != 200 {
+       if err != nil {
                if buildV {
-                       if err != nil {
-                               log.Printf("https fetch failed.")
-                       } else {
-                               log.Printf("ignoring https fetch with status code %d", res.StatusCode)
-                       }
+                       log.Printf("https fetch failed: %v", err)
                }
-               closeBody(res)
                if security == insecure {
+                       closeBody(res)
                        urlStr, res, err = fetch("http")
                }
        }
index 35c7cc4f2a73a8168570695625c88f6a2b56700e..8f741a636b1700219a972fca935a9c97e233ffa9 100644 (file)
@@ -78,6 +78,14 @@ syntax of package template.  The default output is equivalent to -f
         XTestImports []string // imports from XTestGoFiles
     }
 
+The error information, if any, is
+
+    type PackageError struct {
+        ImportStack   []string // shortest path from package named on command line to this one
+        Pos           string   // position of error (if present, file:line:col)
+        Err           string   // the error itself
+    }
+
 The template function "join" calls strings.Join.
 
 The template function "context" returns the build context, defined as:
index 8ebde8925990dc5a4ad1f19a7da298d20302fd8b..c8697ffe98ca3c636606992e27672703d51e1599 100644 (file)
@@ -285,8 +285,8 @@ func printUsage(w io.Writer) {
 func usage() {
        // special case "go test -h"
        if len(os.Args) > 1 && os.Args[1] == "test" {
-               os.Stdout.WriteString(testUsage + "\n\n" +
-                       strings.TrimSpace(testFlag1) + "\n\n" +
+               os.Stderr.WriteString(testUsage + "\n\n" +
+                       strings.TrimSpace(testFlag1) + "\n\n\t" +
                        strings.TrimSpace(testFlag2) + "\n")
                os.Exit(2)
        }
@@ -353,7 +353,7 @@ func importPathsNoDotExpansion(args []string) []string {
                } else {
                        a = path.Clean(a)
                }
-               if a == "all" || a == "std" || a == "cmd" {
+               if isMetaPackage(a) {
                        out = append(out, allPackages(a)...)
                        continue
                }
@@ -554,7 +554,7 @@ func allPackages(pattern string) []string {
 func matchPackages(pattern string) []string {
        match := func(string) bool { return true }
        treeCanMatch := func(string) bool { return true }
-       if pattern != "all" && pattern != "std" && pattern != "cmd" {
+       if !isMetaPackage(pattern) {
                match = matchPattern(pattern)
                treeCanMatch = treeCanMatchPattern(pattern)
        }
@@ -588,10 +588,9 @@ func matchPackages(pattern string) []string {
                        }
 
                        name := filepath.ToSlash(path[len(src):])
-                       if pattern == "std" && (strings.Contains(name, ".") || name == "cmd") {
+                       if pattern == "std" && (!isStandardImportPath(name) || name == "cmd") {
                                // The name "std" is only the standard library.
-                               // If the name has a dot, assume it's a domain name for go get,
-                               // and if the name is cmd, it's the root of the command tree.
+                               // If the name is cmd, it's the root of the command tree.
                                return filepath.SkipDir
                        }
                        if !treeCanMatch(name) {
@@ -674,7 +673,14 @@ func matchPackagesInFS(pattern string) []string {
                if !match(name) {
                        return nil
                }
-               if _, err = build.ImportDir(path, 0); err != nil {
+
+               // We keep the directory if we can import it, or if we can't import it
+               // due to invalid Go source files. This means that directories containing
+               // parse errors will be built (and fail) instead of being silently skipped
+               // as not matching the pattern. Go 1.5 and earlier skipped, but that
+               // behavior means people miss serious mistakes.
+               // See golang.org/issue/11407.
+               if p, err := buildContext.ImportDir(path, 0); err != nil && (p == nil || len(p.InvalidGoFiles) == 0) {
                        if _, noGo := err.(*build.NoGoError); !noGo {
                                log.Print(err)
                        }
index 97e18651e4acca486f3ab3383ab07b1ad872c433..f846eeb62b1cc22872720553f11413e98d9f9eb6 100644 (file)
@@ -7,6 +7,7 @@ package main
 import (
        "bytes"
        "debug/elf"
+       "debug/macho"
        "encoding/binary"
        "fmt"
        "io"
@@ -69,11 +70,11 @@ func readELFNote(filename, name string, typ int32) ([]byte, error) {
 
 var elfGoNote = []byte("Go\x00\x00")
 
-// readELFGoBuildID the Go build ID string from an ELF binary.
-// The Go build ID is stored in a note described by an ELF PT_NOTE prog header.
-// The caller has already opened filename, to get f, and read the first 4 kB out, in data.
+// The Go build ID is stored in a note described by an ELF PT_NOTE prog
+// header.  The caller has already opened filename, to get f, and read
+// at least 4 kB out, in data.
 func readELFGoBuildID(filename string, f *os.File, data []byte) (buildid string, err error) {
-       // Assume the note content is in the first 4 kB, already read.
+       // Assume the note content is in the data, already read.
        // Rewrite the ELF header to set shnum to 0, so that we can pass
        // the data to elf.NewFile and it will decode the Prog list but not
        // try to read the section headers and the string table from disk.
@@ -95,22 +96,92 @@ func readELFGoBuildID(filename string, f *os.File, data []byte) (buildid string,
                return "", &os.PathError{Path: filename, Op: "parse", Err: err}
        }
        for _, p := range ef.Progs {
-               if p.Type != elf.PT_NOTE || p.Off >= uint64(len(data)) || p.Off+p.Filesz >= uint64(len(data)) || p.Filesz < 16 {
+               if p.Type != elf.PT_NOTE || p.Filesz < 16 {
                        continue
                }
 
-               note := data[p.Off : p.Off+p.Filesz]
-               nameSize := ef.ByteOrder.Uint32(note)
-               valSize := ef.ByteOrder.Uint32(note[4:])
-               tag := ef.ByteOrder.Uint32(note[8:])
-               name := note[12:16]
-               if nameSize != 4 || 16+valSize > uint32(len(note)) || tag != elfGoBuildIDTag || !bytes.Equal(name, elfGoNote) {
-                       continue
+               var note []byte
+               if p.Off+p.Filesz < uint64(len(data)) {
+                       note = data[p.Off : p.Off+p.Filesz]
+               } else {
+                       // For some linkers, such as the Solaris linker,
+                       // the buildid may not be found in data (which
+                       // likely contains the first 16kB of the file)
+                       // or even the first few megabytes of the file
+                       // due to differences in note segment placement;
+                       // in that case, extract the note data manually.
+                       _, err = f.Seek(int64(p.Off), 0)
+                       if err != nil {
+                               return "", err
+                       }
+
+                       note = make([]byte, p.Filesz)
+                       _, err = io.ReadFull(f, note)
+                       if err != nil {
+                               return "", err
+                       }
                }
 
-               return string(note[16 : 16+valSize]), nil
+               filesz := p.Filesz
+               for filesz >= 16 {
+                       nameSize := ef.ByteOrder.Uint32(note)
+                       valSize := ef.ByteOrder.Uint32(note[4:])
+                       tag := ef.ByteOrder.Uint32(note[8:])
+                       name := note[12:16]
+                       if nameSize == 4 && 16+valSize <= uint32(len(note)) && tag == elfGoBuildIDTag && bytes.Equal(name, elfGoNote) {
+                               return string(note[16 : 16+valSize]), nil
+                       }
+
+                       nameSize = (nameSize + 3) &^ 3
+                       valSize = (valSize + 3) &^ 3
+                       notesz := uint64(12 + nameSize + valSize)
+                       if filesz <= notesz {
+                               break
+                       }
+                       filesz -= notesz
+                       note = note[notesz:]
+               }
        }
 
        // No note. Treat as successful but build ID empty.
        return "", nil
 }
+
+// The Go build ID is stored at the beginning of the Mach-O __text segment.
+// The caller has already opened filename, to get f, and read a few kB out, in data.
+// Sadly, that's not guaranteed to hold the note, because there is an arbitrary amount
+// of other junk placed in the file ahead of the main text.
+func readMachoGoBuildID(filename string, f *os.File, data []byte) (buildid string, err error) {
+       // If the data we want has already been read, don't worry about Mach-O parsing.
+       // This is both an optimization and a hedge against the Mach-O parsing failing
+       // in the future due to, for example, the name of the __text section changing.
+       if b, err := readRawGoBuildID(filename, data); b != "" && err == nil {
+               return b, err
+       }
+
+       mf, err := macho.NewFile(f)
+       if err != nil {
+               return "", &os.PathError{Path: filename, Op: "parse", Err: err}
+       }
+
+       sect := mf.Section("__text")
+       if sect == nil {
+               // Every binary has a __text section. Something is wrong.
+               return "", &os.PathError{Path: filename, Op: "parse", Err: fmt.Errorf("cannot find __text section")}
+       }
+
+       // It should be in the first few bytes, but read a lot just in case,
+       // especially given our past problems on OS X with the build ID moving.
+       // There shouldn't be much difference between reading 4kB and 32kB:
+       // the hard part is getting to the data, not transferring it.
+       n := sect.Size
+       if n > uint64(BuildIDReadSize) {
+               n = uint64(BuildIDReadSize)
+       }
+       buf := make([]byte, n)
+       if _, err := f.ReadAt(buf, int64(sect.Offset)); err != nil {
+               return "", err
+       }
+
+       return readRawGoBuildID(filename, buf)
+}
index 3d644518c6897de348b57f8928f1b2e06b139769..811734b37728fcffd8a989caf8fd539da0cd2421 100644 (file)
@@ -6,11 +6,29 @@ package main_test
 
 import (
        main "cmd/go"
+       "go/build"
        "runtime"
        "testing"
 )
 
 func TestNoteReading(t *testing.T) {
+       testNoteReading(t)
+}
+
+func TestNoteReading2K(t *testing.T) {
+       if runtime.GOOS == "windows" {
+               t.Skipf("2kB is not enough on %s", runtime.GOOS)
+       }
+       // Set BuildIDReadSize to 2kB to exercise Mach-O parsing more strictly.
+       defer func(old int) {
+               main.BuildIDReadSize = old
+       }(main.BuildIDReadSize)
+       main.BuildIDReadSize = 2 * 1024
+
+       testNoteReading(t)
+}
+
+func testNoteReading(t *testing.T) {
        tg := testgo(t)
        defer tg.cleanup()
        tg.tempFile("hello.go", `package main; func main() { print("hello, world\n") }`)
@@ -24,26 +42,25 @@ func TestNoteReading(t *testing.T) {
                t.Fatalf("buildID in hello binary = %q, want %q", id, buildID)
        }
 
-       if runtime.GOOS == "linux" && runtime.GOARCH == "ppc64le" {
-               t.Skipf("skipping - golang.org/issue/11184")
+       switch {
+       case !build.Default.CgoEnabled:
+               t.Skipf("skipping - no cgo, so assuming external linking not available")
+       case runtime.GOOS == "linux" && (runtime.GOARCH == "ppc64le" || runtime.GOARCH == "ppc64"):
+               t.Skipf("skipping - external linking not supported, golang.org/issue/11184")
+       case runtime.GOOS == "linux" && (runtime.GOARCH == "mips64le" || runtime.GOARCH == "mips64"):
+               t.Skipf("skipping - external linking not supported, golang.org/issue/12560")
+       case runtime.GOOS == "openbsd" && runtime.GOARCH == "arm":
+               t.Skipf("skipping - external linking not supported, golang.org/issue/10619")
+       case runtime.GOOS == "plan9":
+               t.Skipf("skipping - external linking not supported")
        }
 
-       switch runtime.GOOS {
-       case "plan9":
-               // no external linking
-               t.Logf("no external linking - skipping linkmode=external test")
-
-       case "solaris":
-               t.Logf("skipping - golang.org/issue/12178")
-
-       default:
-               tg.run("build", "-ldflags", "-buildid="+buildID+" -linkmode=external", "-o", tg.path("hello.exe"), tg.path("hello.go"))
-               id, err := main.ReadBuildIDFromBinary(tg.path("hello.exe"))
-               if err != nil {
-                       t.Fatalf("reading build ID from hello binary (linkmode=external): %v", err)
-               }
-               if id != buildID {
-                       t.Fatalf("buildID in hello binary = %q, want %q (linkmode=external)", id, buildID)
-               }
+       tg.run("build", "-ldflags", "-buildid="+buildID+" -linkmode=external", "-o", tg.path("hello.exe"), tg.path("hello.go"))
+       id, err = main.ReadBuildIDFromBinary(tg.path("hello.exe"))
+       if err != nil {
+               t.Fatalf("reading build ID from hello binary (linkmode=external): %v", err)
+       }
+       if id != buildID {
+               t.Fatalf("buildID in hello binary = %q, want %q (linkmode=external)", id, buildID)
        }
 }
index 3270a8b52364b9e4113ae76ec7251261be976cb1..73ea2066561d496b6bb85ac7145cd82c055aae70 100644 (file)
@@ -118,7 +118,7 @@ func (p *Package) vendored(imports []string) []string {
        seen := make(map[string]bool)
        var all []string
        for _, path := range imports {
-               path, _ = vendoredImportPath(p, path)
+               path = vendoredImportPath(p, path)
                if !seen[path] {
                        seen[path] = true
                        all = append(all, path)
@@ -156,7 +156,7 @@ func (p *Package) copyBuild(pp *build.Package) {
        if buildContext.Compiler == "gccgo" {
                p.Standard = stdpkg[p.ImportPath]
        } else {
-               p.Standard = p.Goroot && p.ImportPath != "" && !strings.Contains(p.ImportPath, ".")
+               p.Standard = p.Goroot && p.ImportPath != "" && isStandardImportPath(p.ImportPath)
        }
        p.GoFiles = pp.GoFiles
        p.CgoFiles = pp.CgoFiles
@@ -181,6 +181,19 @@ func (p *Package) copyBuild(pp *build.Package) {
        p.XTestImports = pp.XTestImports
 }
 
+// isStandardImportPath reports whether $GOROOT/src/path should be considered
+// part of the standard distribution. For historical reasons we allow people to add
+// their own code to $GOROOT instead of using $GOPATH, but we assume that
+// code will start with a domain name (dot in the first element).
+func isStandardImportPath(path string) bool {
+       i := strings.Index(path, "/")
+       if i < 0 {
+               i = len(path)
+       }
+       elem := path[:i]
+       return !strings.Contains(elem, ".")
+}
+
 // A PackageError describes an error loading information about a package.
 type PackageError struct {
        ImportStack   []string // shortest path from package named on command line to this one
@@ -254,11 +267,14 @@ func reloadPackage(arg string, stk *importStack) *Package {
        return loadPackage(arg, stk)
 }
 
-// The Go 1.5 vendoring experiment is enabled by setting GO15VENDOREXPERIMENT=1.
+// The Go 1.5 vendoring experiment was enabled by setting GO15VENDOREXPERIMENT=1.
+// In Go 1.6 this is on by default and is disabled by setting GO15VENDOREXPERIMENT=0.
+// In Go 1.7 the variable will stop having any effect.
 // The variable is obnoxiously long so that years from now when people find it in
 // their profiles and wonder what it does, there is some chance that a web search
 // might answer the question.
-var go15VendorExperiment = os.Getenv("GO15VENDOREXPERIMENT") == "1"
+// There is a copy of this variable in src/go/build/build.go. Delete that one when this one goes away.
+var go15VendorExperiment = os.Getenv("GO15VENDOREXPERIMENT") != "0"
 
 // dirToImportPath returns the pseudo-import path we use for a package
 // outside the Go path.  It begins with _/ and then contains the full path
@@ -314,11 +330,14 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
        importPath := path
        origPath := path
        isLocal := build.IsLocalImport(path)
-       var vendorSearch []string
        if isLocal {
                importPath = dirToImportPath(filepath.Join(srcDir, path))
        } else if mode&useVendor != 0 {
-               path, vendorSearch = vendoredImportPath(parent, path)
+               // We do our own vendor resolution, because we want to
+               // find out the key to use in packageCache without the
+               // overhead of repeated calls to buildContext.Import.
+               // The code is also needed in a few other places anyway.
+               path = vendoredImportPath(parent, path)
                importPath = path
        }
 
@@ -345,29 +364,12 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
        //
        // TODO: After Go 1, decide when to pass build.AllowBinary here.
        // See issue 3268 for mistakes to avoid.
-       bp, err := buildContext.Import(path, srcDir, build.ImportComment)
-
-       // If we got an error from go/build about package not found,
-       // it contains the directories from $GOROOT and $GOPATH that
-       // were searched. Add to that message the vendor directories
-       // that were searched.
-       if err != nil && len(vendorSearch) > 0 {
-               // NOTE(rsc): The direct text manipulation here is fairly awful,
-               // but it avoids defining new go/build API (an exported error type)
-               // late in the Go 1.5 release cycle. If this turns out to be a more general
-               // problem we could define a real error type when the decision can be
-               // considered more carefully.
-               text := err.Error()
-               if strings.Contains(text, "cannot find package \"") && strings.Contains(text, "\" in any of:\n\t") {
-                       old := strings.SplitAfter(text, "\n")
-                       lines := []string{old[0]}
-                       for _, dir := range vendorSearch {
-                               lines = append(lines, "\t"+dir+" (vendor tree)\n")
-                       }
-                       lines = append(lines, old[1:]...)
-                       err = errors.New(strings.Join(lines, ""))
-               }
+       buildMode := build.ImportComment
+       if !go15VendorExperiment || mode&useVendor == 0 || path != origPath {
+               // Not vendoring, or we already found the vendored path.
+               buildMode |= build.IgnoreVendor
        }
+       bp, err := buildContext.Import(path, srcDir, buildMode)
        bp.ImportPath = importPath
        if gobin != "" {
                bp.BinDir = gobin
@@ -377,7 +379,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
                err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)
        }
        p.load(stk, bp, err)
-       if p.Error != nil && len(importPos) > 0 {
+       if p.Error != nil && p.Error.Pos == "" && len(importPos) > 0 {
                pos := importPos[0]
                pos.Filename = shortPath(pos.Filename)
                p.Error.Pos = pos.String()
@@ -411,14 +413,11 @@ func isDir(path string) bool {
 
 // vendoredImportPath returns the expansion of path when it appears in parent.
 // If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path,
-// x/vendor/path, vendor/path, or else stay x/y/z if none of those exist.
+// x/vendor/path, vendor/path, or else stay path if none of those exist.
 // vendoredImportPath returns the expanded path or, if no expansion is found, the original.
-// If no expansion is found, vendoredImportPath also returns a list of vendor directories
-// it searched along the way, to help prepare a useful error message should path turn
-// out not to exist.
-func vendoredImportPath(parent *Package, path string) (found string, searched []string) {
+func vendoredImportPath(parent *Package, path string) (found string) {
        if parent == nil || parent.Root == "" || !go15VendorExperiment {
-               return path, nil
+               return path
        }
        dir := filepath.Clean(parent.Dir)
        root := filepath.Join(parent.Root, "src")
@@ -438,7 +437,7 @@ func vendoredImportPath(parent *Package, path string) (found string, searched []
                        continue
                }
                targ := filepath.Join(dir[:i], vpath)
-               if isDir(targ) {
+               if isDir(targ) && hasGoFiles(targ) {
                        // We started with parent's dir c:\gopath\src\foo\bar\baz\quux\xyzzy.
                        // We know the import path for parent's dir.
                        // We chopped off some number of path elements and
@@ -453,14 +452,26 @@ func vendoredImportPath(parent *Package, path string) (found string, searched []
                                // and found c:\gopath\src\vendor\path.
                                // We chopped \foo\bar (length 8) but the import path is "foo/bar" (length 7).
                                // Use "vendor/path" without any prefix.
-                               return vpath, nil
+                               return vpath
                        }
-                       return parent.ImportPath[:len(parent.ImportPath)-chopped] + "/" + vpath, nil
+                       return parent.ImportPath[:len(parent.ImportPath)-chopped] + "/" + vpath
                }
-               // Note the existence of a vendor directory in case path is not found anywhere.
-               searched = append(searched, targ)
        }
-       return path, searched
+       return path
+}
+
+// hasGoFiles reports whether dir contains any files with names ending in .go.
+// For a vendor check we must exclude directories that contain no .go files.
+// Otherwise it is not possible to vendor just a/b/c and still import the
+// non-vendored a/b. See golang.org/issue/13832.
+func hasGoFiles(dir string) bool {
+       fis, _ := ioutil.ReadDir(dir)
+       for _, fi := range fis {
+               if !fi.IsDir() && strings.HasSuffix(fi.Name(), ".go") {
+                       return true
+               }
+       }
+       return false
 }
 
 // reusePackage reuses package p to satisfy the import at the top
@@ -522,7 +533,7 @@ func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
                i-- // rewind over slash in ".../internal"
        }
        parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)]
-       if hasPathPrefix(filepath.ToSlash(srcDir), filepath.ToSlash(parent)) {
+       if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
                return p
        }
 
@@ -619,7 +630,7 @@ func disallowVendorVisibility(srcDir string, p *Package, stk *importStack) *Pack
                return p
        }
        parent := p.Dir[:truncateTo]
-       if hasPathPrefix(filepath.ToSlash(srcDir), filepath.ToSlash(parent)) {
+       if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
                return p
        }
 
@@ -712,6 +723,7 @@ func expandScanner(err error) error {
 
 var raceExclude = map[string]bool{
        "runtime/race": true,
+       "runtime/msan": true,
        "runtime/cgo":  true,
        "cmd/cgo":      true,
        "syscall":      true,
@@ -725,6 +737,7 @@ var cgoExclude = map[string]bool{
 var cgoSyscallExclude = map[string]bool{
        "runtime/cgo":  true,
        "runtime/race": true,
+       "runtime/msan": true,
 }
 
 // load populates p using information from bp, err, which should
@@ -829,27 +842,40 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
                importPaths = append(importPaths, "syscall")
        }
 
-       // Currently build mode c-shared, or -linkshared, forces
+       // Currently build modes c-shared, pie, and -linkshared force
        // external linking mode, and external linking mode forces an
        // import of runtime/cgo.
-       if p.Name == "main" && !p.Goroot && (buildBuildmode == "c-shared" || buildLinkshared) {
+       if p.Name == "main" && !p.Goroot && (buildBuildmode == "c-shared" || buildBuildmode == "pie" || buildLinkshared) {
                importPaths = append(importPaths, "runtime/cgo")
        }
 
-       // Everything depends on runtime, except runtime and unsafe.
-       if !p.Standard || (p.ImportPath != "runtime" && p.ImportPath != "unsafe") {
+       // Everything depends on runtime, except runtime, its internal
+       // subpackages, and unsafe.
+       if !p.Standard || (p.ImportPath != "runtime" && !strings.HasPrefix(p.ImportPath, "runtime/internal/") && p.ImportPath != "unsafe") {
                importPaths = append(importPaths, "runtime")
                // When race detection enabled everything depends on runtime/race.
                // Exclude certain packages to avoid circular dependencies.
                if buildRace && (!p.Standard || !raceExclude[p.ImportPath]) {
                        importPaths = append(importPaths, "runtime/race")
                }
+               // MSan uses runtime/msan.
+               if buildMSan && (!p.Standard || !raceExclude[p.ImportPath]) {
+                       importPaths = append(importPaths, "runtime/msan")
+               }
                // On ARM with GOARM=5, everything depends on math for the link.
                if p.Name == "main" && goarch == "arm" {
                        importPaths = append(importPaths, "math")
                }
        }
 
+       // Runtime and its internal packages depend on runtime/internal/sys,
+       // so that they pick up the generated zversion.go file.
+       // This can be an issue particularly for runtime/internal/atomic;
+       // see issue 13655.
+       if p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal/")) && p.ImportPath != "runtime/internal/sys" {
+               importPaths = append(importPaths, "runtime/internal/sys")
+       }
+
        // Build list of full paths to all Go files in the package,
        // for use by commands like go fmt.
        p.gofiles = stringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)
@@ -931,6 +957,17 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
                                }
                        }
                }
+               if p.Standard && !p1.Standard && p.Error == nil {
+                       p.Error = &PackageError{
+                               ImportStack: stk.copy(),
+                               Err:         fmt.Sprintf("non-standard import %q in standard package %q", path, p.ImportPath),
+                       }
+                       pos := p.build.ImportPos[path]
+                       if len(pos) > 0 {
+                               p.Error.Pos = pos[0].String()
+                       }
+               }
+
                path = p1.ImportPath
                importPaths[i] = path
                if i < len(p.Imports) {
@@ -1613,15 +1650,24 @@ func packagesAndErrors(args []string) []*Package {
        }
 
        args = importPaths(args)
-       var pkgs []*Package
-       var stk importStack
-       var set = make(map[string]bool)
+       var (
+               pkgs    []*Package
+               stk     importStack
+               seenArg = make(map[string]bool)
+               seenPkg = make(map[*Package]bool)
+       )
 
        for _, arg := range args {
-               if !set[arg] {
-                       pkgs = append(pkgs, loadPackage(arg, &stk))
-                       set[arg] = true
+               if seenArg[arg] {
+                       continue
+               }
+               seenArg[arg] = true
+               pkg := loadPackage(arg, &stk)
+               if seenPkg[pkg] {
+                       continue
                }
+               seenPkg[pkg] = true
+               pkgs = append(pkgs, pkg)
        }
        computeStale(pkgs...)
 
@@ -1792,8 +1838,17 @@ var (
        goBuildEnd    = []byte("\"\n \xff")
 
        elfPrefix = []byte("\x7fELF")
+
+       machoPrefixes = [][]byte{
+               {0xfe, 0xed, 0xfa, 0xce},
+               {0xfe, 0xed, 0xfa, 0xcf},
+               {0xce, 0xfa, 0xed, 0xfe},
+               {0xcf, 0xfa, 0xed, 0xfe},
+       }
 )
 
+var BuildIDReadSize = 32 * 1024 // changed for testing
+
 // ReadBuildIDFromBinary reads the build ID from a binary.
 //
 // ELF binaries store the build ID in a proper PT_NOTE section.
@@ -1808,10 +1863,11 @@ func ReadBuildIDFromBinary(filename string) (id string, err error) {
                return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDUnknown}
        }
 
-       // Read the first 16 kB of the binary file.
+       // Read the first 32 kB of the binary file.
        // That should be enough to find the build ID.
        // In ELF files, the build ID is in the leading headers,
-       // which are typically less than 4 kB, not to mention 16 kB.
+       // which are typically less than 4 kB, not to mention 32 kB.
+       // In Mach-O files, there's no limit, so we have to parse the file.
        // On other systems, we're trying to read enough that
        // we get the beginning of the text segment in the read.
        // The offset where the text segment begins in a hello
@@ -1819,7 +1875,6 @@ func ReadBuildIDFromBinary(filename string) (id string, err error) {
        //
        //      Plan 9: 0x20
        //      Windows: 0x600
-       //      Mach-O: 0x2000
        //
        f, err := os.Open(filename)
        if err != nil {
@@ -1827,7 +1882,7 @@ func ReadBuildIDFromBinary(filename string) (id string, err error) {
        }
        defer f.Close()
 
-       data := make([]byte, 16*1024)
+       data := make([]byte, BuildIDReadSize)
        _, err = io.ReadFull(f, data)
        if err == io.ErrUnexpectedEOF {
                err = nil
@@ -1839,7 +1894,17 @@ func ReadBuildIDFromBinary(filename string) (id string, err error) {
        if bytes.HasPrefix(data, elfPrefix) {
                return readELFGoBuildID(filename, f, data)
        }
+       for _, m := range machoPrefixes {
+               if bytes.HasPrefix(data, m) {
+                       return readMachoGoBuildID(filename, f, data)
+               }
+       }
+
+       return readRawGoBuildID(filename, data)
+}
 
+// readRawGoBuildID finds the raw build ID stored in text segment data.
+func readRawGoBuildID(filename string, data []byte) (id string, err error) {
        i := bytes.Index(data, goBuildPrefix)
        if i < 0 {
                // Missing. Treat as successful but build ID empty.
index 06b9f0ac6ebcb0fe1802756c8355edc86d07b72d..1e7ca2c6fe0f08c0f5c8260f58634780934fee00 100644 (file)
@@ -5,6 +5,9 @@
 package main
 
 import (
+       "io/ioutil"
+       "os"
+       "path/filepath"
        "reflect"
        "strings"
        "testing"
@@ -57,6 +60,15 @@ var parseMetaGoImportsTests = []struct {
                <body>`,
                []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
        },
+       {
+               `<!doctype html><meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
+               []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+       },
+       {
+               // XML doesn't like <div style=position:relative>.
+               `<!doctype html><title>Page Not Found</title><meta name=go-import content="chitin.io/chitin git https://github.com/chitin-io/chitin"><div style=position:relative>DRAFT</div>`,
+               []metaImport{{"chitin.io/chitin", "git", "https://github.com/chitin-io/chitin"}},
+       },
 }
 
 func TestParseMetaGoImports(t *testing.T) {
@@ -71,3 +83,109 @@ func TestParseMetaGoImports(t *testing.T) {
                }
        }
 }
+
+func TestSharedLibName(t *testing.T) {
+       // TODO(avdva) - make these values platform-specific
+       prefix := "lib"
+       suffix := ".so"
+       testData := []struct {
+               args      []string
+               pkgs      []*Package
+               expected  string
+               expectErr bool
+               rootedAt  string
+       }{
+               {
+                       args:     []string{"std"},
+                       pkgs:     []*Package{},
+                       expected: "std",
+               },
+               {
+                       args:     []string{"std", "cmd"},
+                       pkgs:     []*Package{},
+                       expected: "std,cmd",
+               },
+               {
+                       args:     []string{},
+                       pkgs:     []*Package{&Package{ImportPath: "gopkg.in/somelib"}},
+                       expected: "gopkg.in-somelib",
+               },
+               {
+                       args:     []string{"./..."},
+                       pkgs:     []*Package{&Package{ImportPath: "somelib"}},
+                       expected: "somelib",
+                       rootedAt: "somelib",
+               },
+               {
+                       args:     []string{"../somelib", "../somelib"},
+                       pkgs:     []*Package{&Package{ImportPath: "somelib"}},
+                       expected: "somelib",
+               },
+               {
+                       args:     []string{"../lib1", "../lib2"},
+                       pkgs:     []*Package{&Package{ImportPath: "gopkg.in/lib1"}, &Package{ImportPath: "gopkg.in/lib2"}},
+                       expected: "gopkg.in-lib1,gopkg.in-lib2",
+               },
+               {
+                       args: []string{"./..."},
+                       pkgs: []*Package{
+                               &Package{ImportPath: "gopkg.in/dir/lib1"},
+                               &Package{ImportPath: "gopkg.in/lib2"},
+                               &Package{ImportPath: "gopkg.in/lib3"},
+                       },
+                       expected: "gopkg.in",
+                       rootedAt: "gopkg.in",
+               },
+               {
+                       args:      []string{"std", "../lib2"},
+                       pkgs:      []*Package{},
+                       expectErr: true,
+               },
+               {
+                       args:      []string{"all", "./"},
+                       pkgs:      []*Package{},
+                       expectErr: true,
+               },
+               {
+                       args:      []string{"cmd", "fmt"},
+                       pkgs:      []*Package{},
+                       expectErr: true,
+               },
+       }
+       for _, data := range testData {
+               func() {
+                       if data.rootedAt != "" {
+                               tmpGopath, err := ioutil.TempDir("", "gopath")
+                               if err != nil {
+                                       t.Fatal(err)
+                               }
+                               oldGopath := buildContext.GOPATH
+                               defer func() {
+                                       os.RemoveAll(tmpGopath)
+                                       buildContext.GOPATH = oldGopath
+                                       os.Chdir(cwd)
+                               }()
+                               root := filepath.Join(tmpGopath, "src", data.rootedAt)
+                               err = os.MkdirAll(root, 0755)
+                               if err != nil {
+                                       t.Fatal(err)
+                               }
+                               buildContext.GOPATH = tmpGopath
+                               os.Chdir(root)
+                       }
+                       computed, err := libname(data.args, data.pkgs)
+                       if err != nil {
+                               if !data.expectErr {
+                                       t.Errorf("libname returned an error %q, expected a name", err.Error())
+                               }
+                       } else if data.expectErr {
+                               t.Errorf("libname returned %q, expected an error", computed)
+                       } else {
+                               expected := prefix + data.expected + suffix
+                               if expected != computed {
+                                       t.Errorf("libname returned %q, expected %q", computed, expected)
+                               }
+                       }
+               }()
+       }
+}
index f6da373e2522d4b491a58af224859e8d862f39d9..bf10f4f3e91307a4005b738adacbf7066998a0db 100644 (file)
@@ -64,7 +64,7 @@ func printStderr(args ...interface{}) (int, error) {
 }
 
 func runRun(cmd *Command, args []string) {
-       raceInit()
+       instrumentInit()
        buildModeInit()
        var b builder
        b.init()
@@ -89,8 +89,18 @@ func runRun(cmd *Command, args []string) {
                fatalf("%s", p.Error)
        }
        p.omitDWARF = true
-       for _, err := range p.DepsErrors {
-               errorf("%s", err)
+       if len(p.DepsErrors) > 0 {
+               // Since these are errors in dependencies,
+               // the same error might show up multiple times,
+               // once in each package that depends on it.
+               // Only print each once.
+               printed := map[*PackageError]bool{}
+               for _, err := range p.DepsErrors {
+                       if !printed[err] {
+                               printed[err] = true
+                               errorf("%s", err)
+                       }
+               }
        }
        exitIfErrors()
        if p.Name != "main" {
index aadfdf67cceed41f22d9d9cae659ea56d326c534..1cf58920589206987ae3e2d6cd80c58efd3b23d4 100644 (file)
@@ -13,7 +13,6 @@ import (
        "go/doc"
        "go/parser"
        "go/token"
-       "log"
        "os"
        "os/exec"
        "path"
@@ -33,7 +32,7 @@ func init() {
        cmdTest.Run = runTest
 }
 
-const testUsage = "test [-c] [-i] [build and test flags] [packages] [flags for test binary]"
+const testUsage = "test [build/test flags] [packages] [build/test flags & test binary flags]"
 
 var cmdTest = &Command{
        CustomFlags: true,
@@ -68,11 +67,6 @@ non-test installation.
 
 ` + strings.TrimSpace(testFlag1) + ` See 'go help testflag' for details.
 
-If the test binary needs any other flags, they should be presented after the
-package names. The go tool treats as a flag the first argument that begins with
-a minus sign that it does not recognize itself; that argument and all subsequent
-arguments are passed as arguments to the test binary.
-
 For more about build flags, see 'go help build'.
 For more about specifying packages, see 'go help packages'.
 
@@ -83,10 +77,16 @@ See also: go build, go vet.
 const testFlag1 = `
 In addition to the build flags, the flags handled by 'go test' itself are:
 
+       -args
+           Pass the remainder of the command line (everything after -args)
+           to the test binary, uninterpreted and unchanged.
+           Because this flag consumes the remainder of the command line,
+           the package list (if present) must appear before this flag.
+
        -c
-               Compile the test binary to pkg.test but do not run it
-               (where pkg is the last element of the package's import path).
-               The file name can be changed with the -o flag.
+           Compile the test binary to pkg.test but do not run it
+           (where pkg is the last element of the package's import path).
+           The file name can be changed with the -o flag.
 
        -exec xprog
            Run the test binary using xprog. The behavior is the same as
@@ -97,8 +97,8 @@ In addition to the build flags, the flags handled by 'go test' itself are:
            Do not run the test.
 
        -o file
-               Compile the test binary to the named file.
-               The test still runs (unless -c or -i is specified).
+           Compile the test binary to the named file.
+           The test still runs (unless -c or -i is specified).
 
 The test binary also accepts flags that control execution of the test; these
 flags are also accessible by 'go test'.
@@ -207,6 +207,10 @@ const testFlag2 = `
            Allow parallel execution of test functions that call t.Parallel.
            The value of this flag is the maximum number of tests to run
            simultaneously; by default, it is set to the value of GOMAXPROCS.
+           Note that -parallel only applies within a single test binary.
+           The 'go test' command may run tests for different packages
+           in parallel as well, according to the setting of the -p flag
+           (see 'go help build').
 
        -run regexp
            Run only those tests and examples matching the regular
@@ -230,25 +234,63 @@ const testFlag2 = `
            Verbose output: log all tests as they are run. Also print all
            text from Log and Logf calls even if the test succeeds.
 
-The test binary, called pkg.test where pkg is the name of the
-directory containing the package sources, can be invoked directly
-after building it with 'go test -c'. When invoking the test binary
-directly, each of the standard flag names must be prefixed with 'test.',
-as in -test.run=TestMyFunc or -test.v.
+Each of these flags is also recognized with an optional 'test.' prefix,
+as in -test.v. When invoking the generated test binary (the result of
+'go test -c') directly, however, the prefix is mandatory.
+
+The 'go test' command rewrites or removes recognized flags,
+as appropriate, both before and after the optional package list,
+before invoking the test binary.
 
-When running 'go test', flags not listed above are passed through
-unaltered. For instance, the command
+For instance, the command
 
-       go test -x -v -cpuprofile=prof.out -dir=testdata -update
+       go test -v -myflag testdata -cpuprofile=prof.out -x
 
 will compile the test binary and then run it as
 
-       pkg.test -test.v -test.cpuprofile=prof.out -dir=testdata -update
+       pkg.test -test.v -myflag testdata -test.cpuprofile=prof.out
+
+(The -x flag is removed because it applies only to the go command's
+execution, not to the test itself.)
 
 The test flags that generate profiles (other than for coverage) also
 leave the test binary in pkg.test for use when analyzing the profiles.
 
-Flags not recognized by 'go test' must be placed after any specified packages.
+When 'go test' runs a test binary, it does so from within the 
+corresponding package's source code directory. Depending on the test,
+it may be necessary to do the same when invoking a generated test
+binary directly.
+
+The command-line package list, if present, must appear before any
+flag not known to the go test command. Continuing the example above,
+the package list would have to appear before -myflag, but could appear
+on either side of -v.
+
+To keep an argument for a test binary from being interpreted as a
+known flag or a package name, use -args (see 'go help test') which
+passes the remainder of the command line through to the test binary
+uninterpreted and unaltered.
+
+For instance, the command
+
+       go test -v -args -x -v
+
+will compile the test binary and then run it as
+
+       pkg.test -test.v -x -v
+
+Similarly,
+
+       go test -args math
+
+will compile the test binary and then run it as
+
+       pkg.test math
+
+In the first example, the -x and the second -v are passed through to the
+test binary unchanged and with no effect on the go command itself.
+In the second example, the argument math is passed through to the test
+binary, instead of being interpreted as the package list.
 `
 
 var helpTestfunc = &Command{
@@ -328,7 +370,7 @@ func runTest(cmd *Command, args []string) {
 
        findExecCmd() // initialize cached result
 
-       raceInit()
+       instrumentInit()
        buildModeInit()
        pkgs := packagesForBuild(pkgArgs)
        if len(pkgs) == 0 {
@@ -396,7 +438,7 @@ func runTest(cmd *Command, args []string) {
                if deps["C"] {
                        delete(deps, "C")
                        deps["runtime/cgo"] = true
-                       if goos == runtime.GOOS && goarch == runtime.GOARCH && !buildRace {
+                       if goos == runtime.GOOS && goarch == runtime.GOARCH && !buildRace && !buildMSan {
                                deps["cmd/cgo"] = true
                        }
                }
@@ -442,7 +484,7 @@ func runTest(cmd *Command, args []string) {
                }
                for _, p := range testCoverPkgs {
                        if !used[p.ImportPath] {
-                               log.Printf("warning: no packages being tested depend on %s", p.ImportPath)
+                               fmt.Fprintf(os.Stderr, "warning: no packages being tested depend on %s\n", p.ImportPath)
                        }
                }
 
@@ -547,6 +589,9 @@ func runTest(cmd *Command, args []string) {
                if buildRace {
                        extraOpts = "-race "
                }
+               if buildMSan {
+                       extraOpts = "-msan "
+               }
                fmt.Fprintf(os.Stderr, "installing these packages with 'go test %s-i%s' will speed future tests.\n\n", extraOpts, args)
        }
 
@@ -829,10 +874,12 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
                }
        }
 
-       // writeTestmain writes _testmain.go. This must happen after recompileForTest,
-       // because recompileForTest modifies XXX.
-       if err := writeTestmain(filepath.Join(testDir, "_testmain.go"), t); err != nil {
-               return nil, nil, nil, err
+       if !buildN {
+               // writeTestmain writes _testmain.go. This must happen after recompileForTest,
+               // because recompileForTest modifies XXX.
+               if err := writeTestmain(filepath.Join(testDir, "_testmain.go"), t); err != nil {
+                       return nil, nil, nil, err
+               }
        }
 
        computeStale(pmain)
diff --git a/libgo/go/cmd/go/testdata/flag_test.go b/libgo/go/cmd/go/testdata/flag_test.go
new file mode 100644 (file)
index 0000000..ddf613d
--- /dev/null
@@ -0,0 +1,16 @@
+package flag_test
+
+import (
+       "flag"
+       "log"
+       "testing"
+)
+
+var v = flag.Int("v", 0, "v flag")
+
+// Run this as go test pkg -v=7
+func TestVFlagIsSet(t *testing.T) {
+       if *v != 7 {
+               log.Fatal("v flag not set")
+       }
+}
diff --git a/libgo/go/cmd/go/testdata/src/run/bad.go b/libgo/go/cmd/go/testdata/src/run/bad.go
new file mode 100644 (file)
index 0000000..c1cc3ac
--- /dev/null
@@ -0,0 +1,5 @@
+package main
+
+import _ "run/subdir/internal/private"
+
+func main() {}
diff --git a/libgo/go/cmd/go/testdata/src/run/good.go b/libgo/go/cmd/go/testdata/src/run/good.go
new file mode 100644 (file)
index 0000000..0b67dce
--- /dev/null
@@ -0,0 +1,5 @@
+package main
+
+import _ "run/internal"
+
+func main() {}
diff --git a/libgo/go/cmd/go/testdata/src/run/internal/internal.go b/libgo/go/cmd/go/testdata/src/run/internal/internal.go
new file mode 100644 (file)
index 0000000..5bf0569
--- /dev/null
@@ -0,0 +1 @@
+package internal
diff --git a/libgo/go/cmd/go/testdata/src/run/subdir/internal/private/private.go b/libgo/go/cmd/go/testdata/src/run/subdir/internal/private/private.go
new file mode 100644 (file)
index 0000000..735e4dc
--- /dev/null
@@ -0,0 +1 @@
+package private
diff --git a/libgo/go/cmd/go/testdata/src/vend/dir1/dir1.go b/libgo/go/cmd/go/testdata/src/vend/dir1/dir1.go
new file mode 100644 (file)
index 0000000..b719ead
--- /dev/null
@@ -0,0 +1 @@
+package dir1
index 5e72ada9387a7a79d903d8557b214c0899c432d5..7190f599d68ca8b543ca7c55e1a870973cea1972 100644 (file)
@@ -7,6 +7,6 @@ import (
 
 func TestMsgInternal(t *testing.T) {
        if strings.Msg != "hello, world" {
-               t.Fatal("unexpected msg: %v", strings.Msg)
+               t.Fatalf("unexpected msg: %v", strings.Msg)
        }
 }
index 96e6049dad0ae1642f9fbdcb3a91917675ecd52d..3f2165bd38abea1c76ebf20edcfce8478c3b9ce6 100644 (file)
@@ -7,6 +7,6 @@ import (
 
 func TestMsgExternal(t *testing.T) {
        if strings.Msg != "hello, world" {
-               t.Fatal("unexpected msg: %v", strings.Msg)
+               t.Fatalf("unexpected msg: %v", strings.Msg)
        }
 }
diff --git a/libgo/go/cmd/go/testdata/src/vend/vendor/vend/dir1/dir2/dir2.go b/libgo/go/cmd/go/testdata/src/vend/vendor/vend/dir1/dir2/dir2.go
new file mode 100644 (file)
index 0000000..6fe35e9
--- /dev/null
@@ -0,0 +1 @@
+package dir2
index ae526ebdda252e8fb618fb5b6f90e5ab6902a432..bdcde575c99eb063b08cd6b9305c776def2361da 100644 (file)
@@ -3,3 +3,5 @@ package x
 import _ "p"
 import _ "q"
 import _ "r"
+import _ "vend/dir1"      // not vendored
+import _ "vend/dir1/dir2" // vendored
index 1f3e3d316af5a8794e8746e6617d9a943a5fc3a3..873df1ffc36ce7434f2022fb35bfa6d4e1371e3c 100644 (file)
@@ -87,6 +87,7 @@ func init() {
 func testFlags(args []string) (packageNames, passToTest []string) {
        inPkg := false
        outputDir := ""
+       var explicitArgs []string
        for i := 0; i < len(args); i++ {
                if !strings.HasPrefix(args[i], "-") {
                        if !inPkg && packageNames == nil {
@@ -114,6 +115,12 @@ func testFlags(args []string) (packageNames, passToTest []string) {
                                // make non-nil: we have seen the empty package list
                                packageNames = []string{}
                        }
+                       if args[i] == "-args" || args[i] == "--args" {
+                               // -args or --args signals that everything that follows
+                               // should be passed to the test.
+                               explicitArgs = args[i+1:]
+                               break
+                       }
                        passToTest = append(passToTest, args[i])
                        continue
                }
@@ -191,6 +198,8 @@ func testFlags(args []string) (packageNames, passToTest []string) {
                }
                passToTest = append(passToTest, "-test.outputdir", dir)
        }
+
+       passToTest = append(passToTest, explicitArgs...)
        return
 }
 
index 4b9493937aa1a34bbf18a37f923219a5a9885015..9a552d6ec0123bd6226272e8cc9cea2ce7341123 100644 (file)
@@ -104,6 +104,7 @@ func runTool(cmd *Command, args []string) {
                fmt.Printf("%s\n", cmd)
                return
        }
+       args[0] = toolPath // in case the tool wants to re-exec itself, e.g. cmd/dist
        toolCmd := &exec.Cmd{
                Path:   toolPath,
                Args:   args,
index 28a7540dfe43c0b14f929e94051a74eb6b1ae399..074dd8b2b1259bb7bb7105af9b474b5009bd76c0 100644 (file)
@@ -122,7 +122,7 @@ var vcsGit = &vcsCmd{
        name: "Git",
        cmd:  "git",
 
-       createCmd:   []string{"clone {repo} {dir}", "--git-dir={dir}/.git submodule update --init --recursive"},
+       createCmd:   []string{"clone {repo} {dir}", "-C {dir} submodule update --init --recursive"},
        downloadCmd: []string{"pull --ff-only", "submodule update --init --recursive"},
 
        tagCmd: []tagCmd{
@@ -137,8 +137,9 @@ var vcsGit = &vcsCmd{
        // both createCmd and downloadCmd update the working dir.
        // No need to do more here. We used to 'checkout master'
        // but that doesn't work if the default branch is not named master.
+       // DO NOT add 'checkout master' here.
        // See golang.org/issue/9032.
-       tagSyncDefault: []string{"checkout master", "submodule update --init --recursive"},
+       tagSyncDefault: []string{"submodule update --init --recursive"},
 
        scheme:     []string{"git", "https", "http", "git+ssh", "ssh"},
        pingCmd:    "ls-remote {scheme}://{repo}",
@@ -385,9 +386,6 @@ func (v *vcsCmd) create(dir, repo string) error {
 
 // download downloads any new changes for the repo in dir.
 func (v *vcsCmd) download(dir string) error {
-       if err := v.fixDetachedHead(dir); err != nil {
-               return err
-       }
        for _, cmd := range v.downloadCmd {
                if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
                        continue
@@ -399,30 +397,6 @@ func (v *vcsCmd) download(dir string) error {
        return nil
 }
 
-// fixDetachedHead switches a Git repository in dir from a detached head to the master branch.
-// Go versions before 1.2 downloaded Git repositories in an unfortunate way
-// that resulted in the working tree state being on a detached head.
-// That meant the repository was not usable for normal Git operations.
-// Go 1.2 fixed that, but we can't pull into a detached head, so if this is
-// a Git repository we check for being on a detached head and switch to the
-// real branch, almost always called "master".
-// TODO(dsymonds): Consider removing this for Go 1.3.
-func (v *vcsCmd) fixDetachedHead(dir string) error {
-       if v != vcsGit {
-               return nil
-       }
-
-       // "git symbolic-ref HEAD" succeeds iff we are not on a detached head.
-       if err := v.runVerboseOnly(dir, "symbolic-ref HEAD"); err == nil {
-               // not on a detached head
-               return nil
-       }
-       if buildV {
-               log.Printf("%s on detached head; repairing", dir)
-       }
-       return v.run(dir, "checkout master")
-}
-
 // tags returns the list of available tags for the repo in dir.
 func (v *vcsCmd) tags(dir string) ([]string, error) {
        var tags []string
@@ -567,16 +541,8 @@ func repoRootForImportPath(importPath string, security securityMode) (*repoRoot,
                        lookup = lookup[:i]
                }
                rr, err = repoRootForImportDynamic(lookup, security)
-
-               // repoRootForImportDynamic returns error detail
-               // that is irrelevant if the user didn't intend to use a
-               // dynamic import in the first place.
-               // Squelch it.
                if err != nil {
-                       if buildV {
-                               log.Printf("import %q: %v", importPath, err)
-                       }
-                       err = fmt.Errorf("unrecognized import path %q", importPath)
+                       err = fmt.Errorf("unrecognized import path %q (%v)", importPath, err)
                }
        }
        if err != nil {
@@ -891,7 +857,7 @@ var vcsPaths = []*vcsPath{
        // General syntax for any server.
        // Must be last.
        {
-               re:   `^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?P<vcs>bzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`,
+               re:   `^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?(/~?[A-Za-z0-9_.\-]+)+?)\.(?P<vcs>bzr|git|hg|svn))(/~?[A-Za-z0-9_.\-]+)*$`,
                ping: true,
        },
 }
index f5d5e4f4f0b521a5ccbe99b5039a0ee95965fd7b..a90c2061edb2505fea67e84d98373b5748a29c55 100644 (file)
@@ -18,14 +18,14 @@ func TestRepoRootForImportPath(t *testing.T) {
                path string
                want *repoRoot
        }{
-               {
+               /*{
                        "code.google.com/p/go",
                        &repoRoot{
                                vcs:  vcsHg,
                                repo: "https://code.google.com/p/go",
                        },
                },
-               /*{
+               {
                        "code.google.com/r/go",
                        &repoRoot{
                                vcs:  vcsHg,
index 1e8cf9c8d26d7531fbc5520f5819362c5b21e2a3..006a8c9d3f4324ed32836049ad37001c255bee30 100644 (file)
@@ -24,12 +24,14 @@ func TestVendorImports(t *testing.T) {
        tg.run("list", "-f", "{{.ImportPath}} {{.Imports}}", "vend/...")
        want := `
                vend [vend/vendor/p r]
+               vend/dir1 []
                vend/hello [fmt vend/vendor/strings]
                vend/subdir [vend/vendor/p r]
                vend/vendor/p []
                vend/vendor/q []
                vend/vendor/strings []
-               vend/x [vend/x/vendor/p vend/vendor/q vend/x/vendor/r]
+               vend/vendor/vend/dir1/dir2 []
+               vend/x [vend/x/vendor/p vend/vendor/q vend/x/vendor/r vend/dir1 vend/vendor/vend/dir1/dir2]
                vend/x/invalid [vend/x/invalid/vendor/foo]
                vend/x/vendor/p []
                vend/x/vendor/p/p [notfound]
@@ -45,6 +47,14 @@ func TestVendorImports(t *testing.T) {
        }
 }
 
+func TestVendorBuild(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+       tg.setenv("GO15VENDOREXPERIMENT", "1")
+       tg.run("build", "vend/x")
+}
+
 func TestVendorRun(t *testing.T) {
        tg := testgo(t)
        defer tg.cleanup()
@@ -102,7 +112,7 @@ func TestVendorImportError(t *testing.T) {
 
        re := regexp.MustCompile(`cannot find package "notfound" in any of:
        .*[\\/]testdata[\\/]src[\\/]vend[\\/]x[\\/]vendor[\\/]notfound \(vendor tree\)
-       .*[\\/]testdata[\\/]src[\\/]vend[\\/]vendor[\\/]notfound \(vendor tree\)
+       .*[\\/]testdata[\\/]src[\\/]vend[\\/]vendor[\\/]notfound
        .*[\\/]src[\\/]notfound \(from \$GOROOT\)
        .*[\\/]testdata[\\/]src[\\/]notfound \(from \$GOPATH\)`)
 
@@ -187,6 +197,18 @@ func TestVendorGetUpdate(t *testing.T) {
        tg.run("get", "-u", "github.com/rsc/go-get-issue-11864")
 }
 
+func TestGetSubmodules(t *testing.T) {
+       testenv.MustHaveExternalNetwork(t)
+
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.makeTempdir()
+       tg.setenv("GOPATH", tg.path("."))
+       tg.setenv("GO15VENDOREXPERIMENT", "1")
+       tg.run("get", "-d", "github.com/rsc/go-get-issue-12612")
+       tg.run("get", "-u", "-d", "github.com/rsc/go-get-issue-12612")
+}
+
 func TestVendorCache(t *testing.T) {
        tg := testgo(t)
        defer tg.cleanup()
index b2805ac05fbcc936c92ccd74d4c79781090bb2b5..cfebeffe4a673575e9d088b5d41836878a0b65d9 100644 (file)
@@ -13,7 +13,6 @@ import (
        "go/printer"
        "go/scanner"
        "go/token"
-       "internal/format"
        "io"
        "io/ioutil"
        "os"
@@ -88,7 +87,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
                return err
        }
 
-       file, sourceAdj, indentAdj, err := format.Parse(fileSet, filename, src, stdin)
+       file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, stdin)
        if err != nil {
                return err
        }
@@ -107,7 +106,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
                simplify(file)
        }
 
-       res, err := format.Format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth})
+       res, err := format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth})
        if err != nil {
                return err
        }
diff --git a/libgo/go/cmd/gofmt/internal.go b/libgo/go/cmd/gofmt/internal.go
new file mode 100644 (file)
index 0000000..f764b10
--- /dev/null
@@ -0,0 +1,176 @@
+// Copyright 2015 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.
+
+// TODO(gri): This file and the file src/go/format/internal.go are
+// the same (but for this comment and the package name). Do not modify
+// one without the other. Determine if we can factor out functionality
+// in a public API. See also #11844 for context.
+
+package main
+
+import (
+       "bytes"
+       "go/ast"
+       "go/parser"
+       "go/printer"
+       "go/token"
+       "strings"
+)
+
+// parse parses src, which was read from the named file,
+// as a Go source file, declaration, or statement list.
+func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
+       file *ast.File,
+       sourceAdj func(src []byte, indent int) []byte,
+       indentAdj int,
+       err error,
+) {
+       // Try as whole source file.
+       file, err = parser.ParseFile(fset, filename, src, parserMode)
+       // If there's no error, return.  If the error is that the source file didn't begin with a
+       // package line and source fragments are ok, fall through to
+       // try as a source fragment.  Stop and return on any other error.
+       if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") {
+               return
+       }
+
+       // If this is a declaration list, make it a source file
+       // by inserting a package clause.
+       // Insert using a ;, not a newline, so that the line numbers
+       // in psrc match the ones in src.
+       psrc := append([]byte("package p;"), src...)
+       file, err = parser.ParseFile(fset, filename, psrc, parserMode)
+       if err == nil {
+               sourceAdj = func(src []byte, indent int) []byte {
+                       // Remove the package clause.
+                       // Gofmt has turned the ; into a \n.
+                       src = src[indent+len("package p\n"):]
+                       return bytes.TrimSpace(src)
+               }
+               return
+       }
+       // If the error is that the source file didn't begin with a
+       // declaration, fall through to try as a statement list.
+       // Stop and return on any other error.
+       if !strings.Contains(err.Error(), "expected declaration") {
+               return
+       }
+
+       // If this is a statement list, make it a source file
+       // by inserting a package clause and turning the list
+       // into a function body.  This handles expressions too.
+       // Insert using a ;, not a newline, so that the line numbers
+       // in fsrc match the ones in src. Add an extra '\n' before the '}'
+       // to make sure comments are flushed before the '}'.
+       fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '\n', '}')
+       file, err = parser.ParseFile(fset, filename, fsrc, parserMode)
+       if err == nil {
+               sourceAdj = func(src []byte, indent int) []byte {
+                       // Cap adjusted indent to zero.
+                       if indent < 0 {
+                               indent = 0
+                       }
+                       // Remove the wrapping.
+                       // Gofmt has turned the ; into a \n\n.
+                       // There will be two non-blank lines with indent, hence 2*indent.
+                       src = src[2*indent+len("package p\n\nfunc _() {"):]
+                       // Remove only the "}\n" suffix: remaining whitespaces will be trimmed anyway
+                       src = src[:len(src)-len("}\n")]
+                       return bytes.TrimSpace(src)
+               }
+               // Gofmt has also indented the function body one level.
+               // Adjust that with indentAdj.
+               indentAdj = -1
+       }
+
+       // Succeeded, or out of options.
+       return
+}
+
+// format formats the given package file originally obtained from src
+// and adjusts the result based on the original source via sourceAdj
+// and indentAdj.
+func format(
+       fset *token.FileSet,
+       file *ast.File,
+       sourceAdj func(src []byte, indent int) []byte,
+       indentAdj int,
+       src []byte,
+       cfg printer.Config,
+) ([]byte, error) {
+       if sourceAdj == nil {
+               // Complete source file.
+               var buf bytes.Buffer
+               err := cfg.Fprint(&buf, fset, file)
+               if err != nil {
+                       return nil, err
+               }
+               return buf.Bytes(), nil
+       }
+
+       // Partial source file.
+       // Determine and prepend leading space.
+       i, j := 0, 0
+       for j < len(src) && isSpace(src[j]) {
+               if src[j] == '\n' {
+                       i = j + 1 // byte offset of last line in leading space
+               }
+               j++
+       }
+       var res []byte
+       res = append(res, src[:i]...)
+
+       // Determine and prepend indentation of first code line.
+       // Spaces are ignored unless there are no tabs,
+       // in which case spaces count as one tab.
+       indent := 0
+       hasSpace := false
+       for _, b := range src[i:j] {
+               switch b {
+               case ' ':
+                       hasSpace = true
+               case '\t':
+                       indent++
+               }
+       }
+       if indent == 0 && hasSpace {
+               indent = 1
+       }
+       for i := 0; i < indent; i++ {
+               res = append(res, '\t')
+       }
+
+       // Format the source.
+       // Write it without any leading and trailing space.
+       cfg.Indent = indent + indentAdj
+       var buf bytes.Buffer
+       err := cfg.Fprint(&buf, fset, file)
+       if err != nil {
+               return nil, err
+       }
+       out := sourceAdj(buf.Bytes(), cfg.Indent)
+
+       // If the adjusted output is empty, the source
+       // was empty but (possibly) for white space.
+       // The result is the incoming source.
+       if len(out) == 0 {
+               return src, nil
+       }
+
+       // Otherwise, append output to leading space.
+       res = append(res, out...)
+
+       // Determine and append trailing space.
+       i = len(src)
+       for i > 0 && isSpace(src[i-1]) {
+               i--
+       }
+       return append(res, src[i:]...), nil
+}
+
+// isSpace reports whether the byte is a space character.
+// isSpace defines a space as being among the following bytes: ' ', '\t', '\n' and '\r'.
+func isSpace(b byte) bool {
+       return b == ' ' || b == '\t' || b == '\n' || b == '\r'
+}
index df9a878df44db12eb844b82451f3afc5dbcd9174..237b86021bf356d357077d9f61dacb980f7a39e8 100644 (file)
@@ -15,7 +15,6 @@ import (
        "go/ast"
        "go/printer"
        "go/token"
-       "internal/format"
        "io"
        "os"
        "path/filepath"
@@ -33,7 +32,7 @@ var (
 )
 
 func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error {
-       f, _, _, err := format.Parse(fset, filename, src.Bytes(), false)
+       f, _, _, err := parse(fset, filename, src.Bytes(), false)
        if err != nil {
                return err
        }
@@ -61,7 +60,7 @@ func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) {
 
        // exclude files w/ syntax errors (typically test cases)
        fset := token.NewFileSet()
-       if _, _, _, err = format.Parse(fset, filename, b1.Bytes(), false); err != nil {
+       if _, _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil {
                if *verbose {
                        fmt.Fprintf(os.Stderr, "ignoring %s\n", err)
                }
diff --git a/libgo/go/cmd/gofmt/testdata/old.golden b/libgo/go/cmd/gofmt/testdata/old.golden
deleted file mode 100644 (file)
index 95a0b72..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-package P
-
-func f() {
-       if x {
-               y
-       } else {
-               z
-       }
-}
diff --git a/libgo/go/cmd/gofmt/testdata/old.input b/libgo/go/cmd/gofmt/testdata/old.input
deleted file mode 100644 (file)
index e24eed2..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-package P
-
-func f() {
-       if x {
-               y
-       } else
-               z
-}
index 32d1036ae1b759df5f4094e5641867e1b8555038..ab1d60651436bd5a0b8118b46d5bb7f58c24869a 100644 (file)
@@ -77,14 +77,6 @@ func (br *bitReader) ReadBit() bool {
        return n != 0
 }
 
-func (br *bitReader) TryReadBit() (bit byte, ok bool) {
-       if br.bits > 0 {
-               br.bits--
-               return byte(br.n>>br.bits) & 1, true
-       }
-       return 0, false
-}
-
 func (br *bitReader) Err() error {
        return br.err
 }
index 77c50dfe948b6dc9c52b0a693ba50228431bf2d2..7293d4e3beff419504dd22215dcec5805ec78c16 100644 (file)
@@ -173,6 +173,7 @@ const rand3Hex = "1744b384d68c042371244e13500d4bfb98c6244e3d71a5b700224420b59c59
 const (
        digits = iota
        twain
+       random
 )
 
 var testfiles = []string{
@@ -180,8 +181,10 @@ var testfiles = []string{
        // 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.
+       // Twain is Mark Twain's classic English novel.
        twain: "testdata/Mark.Twain-Tom.Sawyer.txt.bz2",
+       // 16KB of random data from /dev/urandom
+       random: "testdata/random.data.bz2",
 }
 
 func benchmarkDecode(b *testing.B, testfile int) {
@@ -198,6 +201,7 @@ func benchmarkDecode(b *testing.B, testfile int) {
 
 func BenchmarkDecodeDigits(b *testing.B) { benchmarkDecode(b, digits) }
 func BenchmarkDecodeTwain(b *testing.B)  { benchmarkDecode(b, twain) }
+func BenchmarkDecodeRand(b *testing.B)   { benchmarkDecode(b, random) }
 
 func TestBufferOverrun(t *testing.T) {
        // Tests https://golang.org/issue/5747.
index 75a6223d8134c42fb41ba9c95050a2bc2c45271e..9d574b9bdef3f3bfe782b19ad450c8d13c109a23 100644 (file)
@@ -38,23 +38,35 @@ func (t *huffmanTree) Decode(br *bitReader) (v uint16) {
 
        for {
                node := &t.nodes[nodeIndex]
-               bit, ok := br.TryReadBit()
-               if !ok && br.ReadBit() {
-                       bit = 1
-               }
-               // bzip2 encodes left as a true bit.
-               if bit != 0 {
-                       // left
-                       if node.left == invalidNodeValue {
-                               return node.leftValue
-                       }
-                       nodeIndex = node.left
+
+               var bit uint16
+               if br.bits > 0 {
+                       // Get next bit - fast path.
+                       br.bits--
+                       bit = 0 - (uint16(br.n>>br.bits) & 1)
                } else {
-                       // right
-                       if node.right == invalidNodeValue {
-                               return node.rightValue
-                       }
-                       nodeIndex = node.right
+                       // Get next bit - slow path.
+                       // Use ReadBits to retrieve a single bit
+                       // from the underling io.ByteReader.
+                       bit = 0 - uint16(br.ReadBits(1))
+               }
+               // now
+               // bit = 0xffff if the next bit was 1
+               // bit = 0x0000 if the next bit was 0
+
+               // 1 means left, 0 means right.
+               //
+               // if bit == 0xffff {
+               //     nodeIndex = node.left
+               // } else {
+               //     nodeIndex = node.right
+               // }
+               nodeIndex = (bit & node.left) | (^bit & node.right)
+
+               if nodeIndex == invalidNodeValue {
+                       // We found a leaf. Use the value of bit to decide
+                       // whether is a left or a right value.
+                       return (bit & node.leftValue) | (^bit & node.rightValue)
                }
        }
 }
index d5d6e732cf1192305a874a79e45f0ee35eb7a3d8..72bc6652c8918d7d27a0b9038fdc74542459745b 100644 (file)
@@ -7,6 +7,7 @@ package flate
 import (
        "bytes"
        "fmt"
+       "internal/testenv"
        "io"
        "io/ioutil"
        "reflect"
@@ -343,6 +344,9 @@ var deflateInflateStringTests = []deflateInflateStringTest{
 }
 
 func TestDeflateInflateString(t *testing.T) {
+       if testing.Short() && testenv.Builder() == "" {
+               t.Skip("skipping in short mode")
+       }
        for _, test := range deflateInflateStringTests {
                gold, err := ioutil.ReadFile(test.filename)
                if err != nil {
@@ -436,7 +440,11 @@ func TestWriterReset(t *testing.T) {
                        t.Fatalf("NewWriter: %v", err)
                }
                buf := []byte("hello world")
-               for i := 0; i < 1024; i++ {
+               n := 1024
+               if testing.Short() {
+                       n = 10
+               }
+               for i := 0; i < n; i++ {
                        w.Write(buf)
                }
                w.Reset(ioutil.Discard)
diff --git a/libgo/go/compress/flate/fixedhuff.go b/libgo/go/compress/flate/fixedhuff.go
deleted file mode 100644 (file)
index 7df8b9a..0000000
+++ /dev/null
@@ -1,78 +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 flate
-
-// autogenerated by go run gen.go -output fixedhuff.go, DO NOT EDIT
-
-var fixedHuffmanDecoder = huffmanDecoder{
-       7,
-       [huffmanNumChunks]uint32{
-               0x1007, 0x0508, 0x0108, 0x1188, 0x1107, 0x0708, 0x0308, 0x0c09,
-               0x1087, 0x0608, 0x0208, 0x0a09, 0x0008, 0x0808, 0x0408, 0x0e09,
-               0x1047, 0x0588, 0x0188, 0x0909, 0x1147, 0x0788, 0x0388, 0x0d09,
-               0x10c7, 0x0688, 0x0288, 0x0b09, 0x0088, 0x0888, 0x0488, 0x0f09,
-               0x1027, 0x0548, 0x0148, 0x11c8, 0x1127, 0x0748, 0x0348, 0x0c89,
-               0x10a7, 0x0648, 0x0248, 0x0a89, 0x0048, 0x0848, 0x0448, 0x0e89,
-               0x1067, 0x05c8, 0x01c8, 0x0989, 0x1167, 0x07c8, 0x03c8, 0x0d89,
-               0x10e7, 0x06c8, 0x02c8, 0x0b89, 0x00c8, 0x08c8, 0x04c8, 0x0f89,
-               0x1017, 0x0528, 0x0128, 0x11a8, 0x1117, 0x0728, 0x0328, 0x0c49,
-               0x1097, 0x0628, 0x0228, 0x0a49, 0x0028, 0x0828, 0x0428, 0x0e49,
-               0x1057, 0x05a8, 0x01a8, 0x0949, 0x1157, 0x07a8, 0x03a8, 0x0d49,
-               0x10d7, 0x06a8, 0x02a8, 0x0b49, 0x00a8, 0x08a8, 0x04a8, 0x0f49,
-               0x1037, 0x0568, 0x0168, 0x11e8, 0x1137, 0x0768, 0x0368, 0x0cc9,
-               0x10b7, 0x0668, 0x0268, 0x0ac9, 0x0068, 0x0868, 0x0468, 0x0ec9,
-               0x1077, 0x05e8, 0x01e8, 0x09c9, 0x1177, 0x07e8, 0x03e8, 0x0dc9,
-               0x10f7, 0x06e8, 0x02e8, 0x0bc9, 0x00e8, 0x08e8, 0x04e8, 0x0fc9,
-               0x1007, 0x0518, 0x0118, 0x1198, 0x1107, 0x0718, 0x0318, 0x0c29,
-               0x1087, 0x0618, 0x0218, 0x0a29, 0x0018, 0x0818, 0x0418, 0x0e29,
-               0x1047, 0x0598, 0x0198, 0x0929, 0x1147, 0x0798, 0x0398, 0x0d29,
-               0x10c7, 0x0698, 0x0298, 0x0b29, 0x0098, 0x0898, 0x0498, 0x0f29,
-               0x1027, 0x0558, 0x0158, 0x11d8, 0x1127, 0x0758, 0x0358, 0x0ca9,
-               0x10a7, 0x0658, 0x0258, 0x0aa9, 0x0058, 0x0858, 0x0458, 0x0ea9,
-               0x1067, 0x05d8, 0x01d8, 0x09a9, 0x1167, 0x07d8, 0x03d8, 0x0da9,
-               0x10e7, 0x06d8, 0x02d8, 0x0ba9, 0x00d8, 0x08d8, 0x04d8, 0x0fa9,
-               0x1017, 0x0538, 0x0138, 0x11b8, 0x1117, 0x0738, 0x0338, 0x0c69,
-               0x1097, 0x0638, 0x0238, 0x0a69, 0x0038, 0x0838, 0x0438, 0x0e69,
-               0x1057, 0x05b8, 0x01b8, 0x0969, 0x1157, 0x07b8, 0x03b8, 0x0d69,
-               0x10d7, 0x06b8, 0x02b8, 0x0b69, 0x00b8, 0x08b8, 0x04b8, 0x0f69,
-               0x1037, 0x0578, 0x0178, 0x11f8, 0x1137, 0x0778, 0x0378, 0x0ce9,
-               0x10b7, 0x0678, 0x0278, 0x0ae9, 0x0078, 0x0878, 0x0478, 0x0ee9,
-               0x1077, 0x05f8, 0x01f8, 0x09e9, 0x1177, 0x07f8, 0x03f8, 0x0de9,
-               0x10f7, 0x06f8, 0x02f8, 0x0be9, 0x00f8, 0x08f8, 0x04f8, 0x0fe9,
-               0x1007, 0x0508, 0x0108, 0x1188, 0x1107, 0x0708, 0x0308, 0x0c19,
-               0x1087, 0x0608, 0x0208, 0x0a19, 0x0008, 0x0808, 0x0408, 0x0e19,
-               0x1047, 0x0588, 0x0188, 0x0919, 0x1147, 0x0788, 0x0388, 0x0d19,
-               0x10c7, 0x0688, 0x0288, 0x0b19, 0x0088, 0x0888, 0x0488, 0x0f19,
-               0x1027, 0x0548, 0x0148, 0x11c8, 0x1127, 0x0748, 0x0348, 0x0c99,
-               0x10a7, 0x0648, 0x0248, 0x0a99, 0x0048, 0x0848, 0x0448, 0x0e99,
-               0x1067, 0x05c8, 0x01c8, 0x0999, 0x1167, 0x07c8, 0x03c8, 0x0d99,
-               0x10e7, 0x06c8, 0x02c8, 0x0b99, 0x00c8, 0x08c8, 0x04c8, 0x0f99,
-               0x1017, 0x0528, 0x0128, 0x11a8, 0x1117, 0x0728, 0x0328, 0x0c59,
-               0x1097, 0x0628, 0x0228, 0x0a59, 0x0028, 0x0828, 0x0428, 0x0e59,
-               0x1057, 0x05a8, 0x01a8, 0x0959, 0x1157, 0x07a8, 0x03a8, 0x0d59,
-               0x10d7, 0x06a8, 0x02a8, 0x0b59, 0x00a8, 0x08a8, 0x04a8, 0x0f59,
-               0x1037, 0x0568, 0x0168, 0x11e8, 0x1137, 0x0768, 0x0368, 0x0cd9,
-               0x10b7, 0x0668, 0x0268, 0x0ad9, 0x0068, 0x0868, 0x0468, 0x0ed9,
-               0x1077, 0x05e8, 0x01e8, 0x09d9, 0x1177, 0x07e8, 0x03e8, 0x0dd9,
-               0x10f7, 0x06e8, 0x02e8, 0x0bd9, 0x00e8, 0x08e8, 0x04e8, 0x0fd9,
-               0x1007, 0x0518, 0x0118, 0x1198, 0x1107, 0x0718, 0x0318, 0x0c39,
-               0x1087, 0x0618, 0x0218, 0x0a39, 0x0018, 0x0818, 0x0418, 0x0e39,
-               0x1047, 0x0598, 0x0198, 0x0939, 0x1147, 0x0798, 0x0398, 0x0d39,
-               0x10c7, 0x0698, 0x0298, 0x0b39, 0x0098, 0x0898, 0x0498, 0x0f39,
-               0x1027, 0x0558, 0x0158, 0x11d8, 0x1127, 0x0758, 0x0358, 0x0cb9,
-               0x10a7, 0x0658, 0x0258, 0x0ab9, 0x0058, 0x0858, 0x0458, 0x0eb9,
-               0x1067, 0x05d8, 0x01d8, 0x09b9, 0x1167, 0x07d8, 0x03d8, 0x0db9,
-               0x10e7, 0x06d8, 0x02d8, 0x0bb9, 0x00d8, 0x08d8, 0x04d8, 0x0fb9,
-               0x1017, 0x0538, 0x0138, 0x11b8, 0x1117, 0x0738, 0x0338, 0x0c79,
-               0x1097, 0x0638, 0x0238, 0x0a79, 0x0038, 0x0838, 0x0438, 0x0e79,
-               0x1057, 0x05b8, 0x01b8, 0x0979, 0x1157, 0x07b8, 0x03b8, 0x0d79,
-               0x10d7, 0x06b8, 0x02b8, 0x0b79, 0x00b8, 0x08b8, 0x04b8, 0x0f79,
-               0x1037, 0x0578, 0x0178, 0x11f8, 0x1137, 0x0778, 0x0378, 0x0cf9,
-               0x10b7, 0x0678, 0x0278, 0x0af9, 0x0078, 0x0878, 0x0478, 0x0ef9,
-               0x1077, 0x05f8, 0x01f8, 0x09f9, 0x1177, 0x07f8, 0x03f8, 0x0df9,
-               0x10f7, 0x06f8, 0x02f8, 0x0bf9, 0x00f8, 0x08f8, 0x04f8, 0x0ff9,
-       },
-       nil, 0,
-}
index 3f67025cd76b5f98ba26bc615dd87a80d28bd583..341d807131351c6ea2a39969537b5e5d609ce687 100644 (file)
@@ -11,7 +11,9 @@ package flate
 import (
        "bytes"
        "encoding/hex"
+       "io"
        "io/ioutil"
+       "strings"
        "testing"
 )
 
@@ -258,3 +260,15 @@ func TestStreams(t *testing.T) {
                }
        }
 }
+
+func TestTruncatedStreams(t *testing.T) {
+       const data = "\x00\f\x00\xf3\xffhello, world\x01\x00\x00\xff\xff"
+
+       for i := 0; i < len(data)-1; i++ {
+               r := NewReader(strings.NewReader(data[:i]))
+               _, err := io.Copy(ioutil.Discard, r)
+               if err != io.ErrUnexpectedEOF {
+                       t.Errorf("io.Copy(%d) on truncated stream: got %v, want %v", i, err, io.ErrUnexpectedEOF)
+               }
+       }
+}
diff --git a/libgo/go/compress/flate/gen.go b/libgo/go/compress/flate/gen.go
deleted file mode 100644 (file)
index 154c89a..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-// Copyright 2012 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 ignore
-
-// This program generates fixedhuff.go
-// Invoke as
-//
-//     go run gen.go -output fixedhuff.go
-
-package main
-
-import (
-       "bytes"
-       "flag"
-       "fmt"
-       "go/format"
-       "io/ioutil"
-       "log"
-)
-
-var filename = flag.String("output", "fixedhuff.go", "output file name")
-
-const maxCodeLen = 16
-
-// Note: the definition of the huffmanDecoder struct is copied from
-// inflate.go, as it is private to the implementation.
-
-// chunk & 15 is number of bits
-// chunk >> 4 is value, including table link
-
-const (
-       huffmanChunkBits  = 9
-       huffmanNumChunks  = 1 << huffmanChunkBits
-       huffmanCountMask  = 15
-       huffmanValueShift = 4
-)
-
-type huffmanDecoder struct {
-       min      int                      // the minimum code length
-       chunks   [huffmanNumChunks]uint32 // chunks as described above
-       links    [][]uint32               // overflow links
-       linkMask uint32                   // mask the width of the link table
-}
-
-// Initialize Huffman decoding tables from array of code lengths.
-// Following this function, h is guaranteed to be initialized into a complete
-// tree (i.e., neither over-subscribed nor under-subscribed). The exception is a
-// degenerate case where the tree has only a single symbol with length 1. Empty
-// trees are permitted.
-func (h *huffmanDecoder) init(bits []int) bool {
-       // Sanity enables additional runtime tests during Huffman
-       // table construction.  It's intended to be used during
-       // development to supplement the currently ad-hoc unit tests.
-       const sanity = false
-
-       if h.min != 0 {
-               *h = huffmanDecoder{}
-       }
-
-       // Count number of codes of each length,
-       // compute min and max length.
-       var count [maxCodeLen]int
-       var min, max int
-       for _, n := range bits {
-               if n == 0 {
-                       continue
-               }
-               if min == 0 || n < min {
-                       min = n
-               }
-               if n > max {
-                       max = n
-               }
-               count[n]++
-       }
-
-       // Empty tree. The decompressor.huffSym function will fail later if the tree
-       // is used. Technically, an empty tree is only valid for the HDIST tree and
-       // not the HCLEN and HLIT tree. However, a stream with an empty HCLEN tree
-       // is guaranteed to fail since it will attempt to use the tree to decode the
-       // codes for the HLIT and HDIST trees. Similarly, an empty HLIT tree is
-       // guaranteed to fail later since the compressed data section must be
-       // composed of at least one symbol (the end-of-block marker).
-       if max == 0 {
-               return true
-       }
-
-       code := 0
-       var nextcode [maxCodeLen]int
-       for i := min; i <= max; i++ {
-               code <<= 1
-               nextcode[i] = code
-               code += count[i]
-       }
-
-       // Check that the coding is complete (i.e., that we've
-       // assigned all 2-to-the-max possible bit sequences).
-       // Exception: To be compatible with zlib, we also need to
-       // accept degenerate single-code codings.  See also
-       // TestDegenerateHuffmanCoding.
-       if code != 1<<uint(max) && !(code == 1 && max == 1) {
-               return false
-       }
-
-       h.min = min
-       if max > huffmanChunkBits {
-               numLinks := 1 << (uint(max) - huffmanChunkBits)
-               h.linkMask = uint32(numLinks - 1)
-
-               // create link tables
-               link := nextcode[huffmanChunkBits+1] >> 1
-               h.links = make([][]uint32, huffmanNumChunks-link)
-               for j := uint(link); j < huffmanNumChunks; j++ {
-                       reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8
-                       reverse >>= uint(16 - huffmanChunkBits)
-                       off := j - uint(link)
-                       if sanity && h.chunks[reverse] != 0 {
-                               panic("impossible: overwriting existing chunk")
-                       }
-                       h.chunks[reverse] = uint32(off<<huffmanValueShift | (huffmanChunkBits + 1))
-                       h.links[off] = make([]uint32, numLinks)
-               }
-       }
-
-       for i, n := range bits {
-               if n == 0 {
-                       continue
-               }
-               code := nextcode[n]
-               nextcode[n]++
-               chunk := uint32(i<<huffmanValueShift | n)
-               reverse := int(reverseByte[code>>8]) | int(reverseByte[code&0xff])<<8
-               reverse >>= uint(16 - n)
-               if n <= huffmanChunkBits {
-                       for off := reverse; off < len(h.chunks); off += 1 << uint(n) {
-                               // We should never need to overwrite
-                               // an existing chunk.  Also, 0 is
-                               // never a valid chunk, because the
-                               // lower 4 "count" bits should be
-                               // between 1 and 15.
-                               if sanity && h.chunks[off] != 0 {
-                                       panic("impossible: overwriting existing chunk")
-                               }
-                               h.chunks[off] = chunk
-                       }
-               } else {
-                       j := reverse & (huffmanNumChunks - 1)
-                       if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 {
-                               // Longer codes should have been
-                               // associated with a link table above.
-                               panic("impossible: not an indirect chunk")
-                       }
-                       value := h.chunks[j] >> huffmanValueShift
-                       linktab := h.links[value]
-                       reverse >>= huffmanChunkBits
-                       for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) {
-                               if sanity && linktab[off] != 0 {
-                                       panic("impossible: overwriting existing chunk")
-                               }
-                               linktab[off] = chunk
-                       }
-               }
-       }
-
-       if sanity {
-               // Above we've sanity checked that we never overwrote
-               // an existing entry.  Here we additionally check that
-               // we filled the tables completely.
-               for i, chunk := range h.chunks {
-                       if chunk == 0 {
-                               // As an exception, in the degenerate
-                               // single-code case, we allow odd
-                               // chunks to be missing.
-                               if code == 1 && i%2 == 1 {
-                                       continue
-                               }
-                               panic("impossible: missing chunk")
-                       }
-               }
-               for _, linktab := range h.links {
-                       for _, chunk := range linktab {
-                               if chunk == 0 {
-                                       panic("impossible: missing chunk")
-                               }
-                       }
-               }
-       }
-
-       return true
-}
-
-func main() {
-       flag.Parse()
-
-       var h huffmanDecoder
-       var bits [288]int
-       initReverseByte()
-       for i := 0; i < 144; i++ {
-               bits[i] = 8
-       }
-       for i := 144; i < 256; i++ {
-               bits[i] = 9
-       }
-       for i := 256; i < 280; i++ {
-               bits[i] = 7
-       }
-       for i := 280; i < 288; i++ {
-               bits[i] = 8
-       }
-       h.init(bits[:])
-       if h.links != nil {
-               log.Fatal("Unexpected links table in fixed Huffman decoder")
-       }
-
-       var buf bytes.Buffer
-
-       fmt.Fprintf(&buf, `// 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.`+"\n\n")
-
-       fmt.Fprintln(&buf, "package flate")
-       fmt.Fprintln(&buf)
-       fmt.Fprintln(&buf, "// autogenerated by go run gen.go -output fixedhuff.go, DO NOT EDIT")
-       fmt.Fprintln(&buf)
-       fmt.Fprintln(&buf, "var fixedHuffmanDecoder = huffmanDecoder{")
-       fmt.Fprintf(&buf, "\t%d,\n", h.min)
-       fmt.Fprintln(&buf, "\t[huffmanNumChunks]uint32{")
-       for i := 0; i < huffmanNumChunks; i++ {
-               if i&7 == 0 {
-                       fmt.Fprintf(&buf, "\t\t")
-               } else {
-                       fmt.Fprintf(&buf, " ")
-               }
-               fmt.Fprintf(&buf, "0x%04x,", h.chunks[i])
-               if i&7 == 7 {
-                       fmt.Fprintln(&buf)
-               }
-       }
-       fmt.Fprintln(&buf, "\t},")
-       fmt.Fprintln(&buf, "\tnil, 0,")
-       fmt.Fprintln(&buf, "}")
-
-       data, err := format.Source(buf.Bytes())
-       if err != nil {
-               log.Fatal(err)
-       }
-       err = ioutil.WriteFile(*filename, data, 0644)
-       if err != nil {
-               log.Fatal(err)
-       }
-}
-
-var reverseByte [256]byte
-
-func initReverseByte() {
-       for x := 0; x < 256; x++ {
-               var result byte
-               for i := uint(0); i < 8; i++ {
-                       result |= byte(((x >> i) & 1) << (7 - i))
-               }
-               reverseByte[x] = result
-       }
-}
index 04372dec2419c86a7f66b9965cfc0d16fffdaa38..42261e9b618eb9dc50b0875327004167cfd4a66b 100644 (file)
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:generate go run gen.go -output fixedhuff.go
-
 // Package flate implements the DEFLATE compressed data format, described in
 // RFC 1951.  The gzip and zlib packages implement access to DEFLATE-based file
 // formats.
@@ -13,6 +11,7 @@ import (
        "bufio"
        "io"
        "strconv"
+       "sync"
 )
 
 const (
@@ -26,6 +25,10 @@ const (
        numCodes   = 19 // number of codes in Huffman meta-code
 )
 
+// Initialize the fixedHuffmanDecoder only once upon first use.
+var fixedOnce sync.Once
+var fixedHuffmanDecoder huffmanDecoder
+
 // A CorruptInputError reports the presence of corrupt input at a given offset.
 type CorruptInputError int64
 
@@ -39,6 +42,8 @@ type InternalError string
 func (e InternalError) Error() string { return "flate: internal error: " + string(e) }
 
 // A ReadError reports an error encountered while reading input.
+//
+// Deprecated: No longer returned.
 type ReadError struct {
        Offset int64 // byte offset where error occurred
        Err    error // error returned by underlying Read
@@ -49,6 +54,8 @@ func (e *ReadError) Error() string {
 }
 
 // A WriteError reports an error encountered while writing output.
+//
+// Deprecated: No longer returned.
 type WriteError struct {
        Offset int64 // byte offset where error occurred
        Err    error // error returned by underlying Write
@@ -67,10 +74,6 @@ type Resetter interface {
        Reset(r io.Reader, dict []byte) error
 }
 
-// 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.
-
 // The data structure for decoding Huffman tables is based on that of
 // zlib. There is a lookup table of a fixed bit width (huffmanChunkBits),
 // For codes smaller than the table width, there are multiple entries
@@ -78,12 +81,15 @@ type Resetter interface {
 // larger than the table width, the table contains a link to an overflow
 // table. The width of each entry in the link table is the maximum code
 // size minus the chunk width.
-
+//
 // Note that you can do a lookup in the table even without all bits
 // filled. Since the extra bits are zero, and the DEFLATE Huffman codes
 // have the property that shorter codes come before longer ones, the
 // bit length estimate in the result is a lower bound on the actual
 // number of bits.
+//
+// See the following:
+//     http://www.gzip.org/algorithm.txt
 
 // chunk & 15 is number of bits
 // chunk >> 4 is value, including table link
@@ -459,6 +465,14 @@ func (f *decompressor) readHuffman() error {
                return CorruptInputError(f.roffset)
        }
 
+       // As an optimization, we can initialize the min bits to read at a time
+       // for the HLIT tree to the length of the EOB marker since we know that
+       // every block must terminate with one. This preserves the property that
+       // we never read any extra bytes after the end of the DEFLATE stream.
+       if f.h1.min < f.bits[endBlockMarker] {
+               f.h1.min = f.bits[endBlockMarker]
+       }
+
        return nil
 }
 
@@ -635,7 +649,10 @@ func (f *decompressor) dataBlock() {
        nr, err := io.ReadFull(f.r, f.buf[0:4])
        f.roffset += int64(nr)
        if err != nil {
-               f.err = &ReadError{f.roffset, err}
+               if err == io.EOF {
+                       err = io.ErrUnexpectedEOF
+               }
+               f.err = err
                return
        }
        n := int(f.buf[0]) | int(f.buf[1])<<8
@@ -667,7 +684,10 @@ func (f *decompressor) copyData() {
                m, err := io.ReadFull(f.r, f.hist[f.hp:f.hp+m])
                f.roffset += int64(m)
                if err != nil {
-                       f.err = &ReadError{f.roffset, err}
+                       if err == io.EOF {
+                               err = io.ErrUnexpectedEOF
+                       }
+                       f.err = err
                        return
                }
                n -= m
@@ -760,6 +780,26 @@ func makeReader(r io.Reader) Reader {
        return bufio.NewReader(r)
 }
 
+func fixedHuffmanDecoderInit() {
+       fixedOnce.Do(func() {
+               // These come from the RFC section 3.2.6.
+               var bits [288]int
+               for i := 0; i < 144; i++ {
+                       bits[i] = 8
+               }
+               for i := 144; i < 256; i++ {
+                       bits[i] = 9
+               }
+               for i := 256; i < 280; i++ {
+                       bits[i] = 7
+               }
+               for i := 280; i < 288; i++ {
+                       bits[i] = 8
+               }
+               fixedHuffmanDecoder.init(bits[:])
+       })
+}
+
 func (f *decompressor) Reset(r io.Reader, dict []byte) error {
        *f = decompressor{
                r:        makeReader(r),
@@ -783,11 +823,13 @@ func (f *decompressor) Reset(r io.Reader, dict []byte) error {
 //
 // The ReadCloser returned by NewReader also implements Resetter.
 func NewReader(r io.Reader) io.ReadCloser {
+       fixedHuffmanDecoderInit()
+
        var f decompressor
-       f.bits = new([maxNumLit + maxNumDist]int)
-       f.codebits = new([numCodes]int)
        f.r = makeReader(r)
        f.hist = new([maxHist]byte)
+       f.bits = new([maxNumLit + maxNumDist]int)
+       f.codebits = new([numCodes]int)
        f.step = (*decompressor).nextBlock
        return &f
 }
@@ -800,6 +842,8 @@ func NewReader(r io.Reader) io.ReadCloser {
 //
 // The ReadCloser returned by NewReader also implements Resetter.
 func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser {
+       fixedHuffmanDecoderInit()
+
        var f decompressor
        f.r = makeReader(r)
        f.hist = new([maxHist]byte)
index a62ef741df336161397cc132cc4bec2ca656cfc1..bd8873239df46bb1d3a6bc9b9c8f9ce034437a6b 100644 (file)
@@ -32,7 +32,7 @@ var testfiles = []string{
        // 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.
+       // Twain is Mark Twain's classic English novel.
        twain: "../testdata/Mark.Twain-Tom.Sawyer.txt",
 }
 
index 4d491768717f8ccd945130ad8ff49618db3d8fa9..c485939d3453b54f5a79c8f7ffa8255973e79ce9 100644 (file)
@@ -90,13 +90,11 @@ func lengthCode(len uint32) uint32 { return lengthCodes[len] }
 
 // Returns the offset code corresponding to a specific offset
 func offsetCode(off uint32) uint32 {
-       const n = uint32(len(offsetCodes))
-       switch {
-       case off < n:
+       if off < uint32(len(offsetCodes)) {
                return offsetCodes[off]
-       case off>>7 < n:
+       }
+       if off>>7 < uint32(len(offsetCodes)) {
                return offsetCodes[off>>7] + 14
-       default:
-               return offsetCodes[off>>14] + 28
        }
+       return offsetCodes[off>>14] + 28
 }
index 72ee55c4fabdf5a310688bd7fda031c389510e1c..3d331454a695bf065c5f1e57170ee5bd16ea98bc 100644 (file)
@@ -43,6 +43,9 @@ var (
 
 // The gzip file stores a header giving metadata about the compressed file.
 // That header is exposed as the fields of the Writer and Reader structs.
+//
+// Strings must be UTF-8 encoded and may only contain Unicode code points
+// U+0001 through U+00FF, due to limitations of the GZIP file format.
 type Header struct {
        Comment string    // comment
        Extra   []byte    // "extra data"
@@ -66,7 +69,7 @@ type Header struct {
 // returned by Read as tentative until they receive the io.EOF
 // marking the end of the data.
 type Reader struct {
-       Header
+       Header       // valid after NewReader or Reader.Reset
        r            flate.Reader
        decompressor io.ReadCloser
        digest       hash.Hash32
@@ -80,7 +83,10 @@ type Reader struct {
 // NewReader creates a new Reader reading the given reader.
 // If r does not also implement io.ByteReader,
 // the decompressor may read more data than necessary from r.
+//
 // It is the caller's responsibility to call Close on the Reader when done.
+//
+// The Reader.Header fields will be valid in the Reader returned.
 func NewReader(r io.Reader) (*Reader, error) {
        z := new(Reader)
        z.r = makeReader(r)
@@ -164,6 +170,9 @@ func (z *Reader) readString() (string, error) {
 func (z *Reader) read2() (uint32, error) {
        _, err := io.ReadFull(z.r, z.buf[0:2])
        if err != nil {
+               if err == io.EOF {
+                       err = io.ErrUnexpectedEOF
+               }
                return 0, err
        }
        return uint32(z.buf[0]) | uint32(z.buf[1])<<8, nil
@@ -172,6 +181,13 @@ func (z *Reader) read2() (uint32, error) {
 func (z *Reader) readHeader(save bool) error {
        _, err := io.ReadFull(z.r, z.buf[0:10])
        if err != nil {
+               // RFC1952 section 2.2 says the following:
+               //      A gzip file consists of a series of "members" (compressed data sets).
+               //
+               // Other than this, the specification does not clarify whether a
+               // "series" is defined as "one or more" or "zero or more". To err on the
+               // side of caution, Go interprets this to mean "zero or more".
+               // Thus, it is okay to return io.EOF here.
                return err
        }
        if z.buf[0] != gzipID1 || z.buf[1] != gzipID2 || z.buf[2] != gzipDeflate {
@@ -193,6 +209,9 @@ func (z *Reader) readHeader(save bool) error {
                }
                data := make([]byte, n)
                if _, err = io.ReadFull(z.r, data); err != nil {
+                       if err == io.EOF {
+                               err = io.ErrUnexpectedEOF
+                       }
                        return err
                }
                if save {
@@ -257,6 +276,9 @@ func (z *Reader) Read(p []byte) (n int, err error) {
 
        // Finished file; check checksum + size.
        if _, err := io.ReadFull(z.r, z.buf[0:8]); err != nil {
+               if err == io.EOF {
+                       err = io.ErrUnexpectedEOF
+               }
                z.err = err
                return 0, err
        }
index 0636dec9ab01d208857673d7f8e566444eda9627..007d9585ceee10acf0779ac88086567432df59b2 100644 (file)
@@ -6,6 +6,7 @@ package gzip
 
 import (
        "bytes"
+       "compress/flate"
        "io"
        "io/ioutil"
        "os"
@@ -408,3 +409,34 @@ Found:
                t.Fatalf("third reset: err=%v, want io.EOF", err)
        }
 }
+
+func TestNilStream(t *testing.T) {
+       // Go liberally interprets RFC1952 section 2.2 to mean that a gzip file
+       // consist of zero or more members. Thus, we test that a nil stream is okay.
+       _, err := NewReader(bytes.NewReader(nil))
+       if err != io.EOF {
+               t.Fatalf("NewReader(nil) on empty stream: got %v, want io.EOF", err)
+       }
+}
+
+func TestTruncatedStreams(t *testing.T) {
+       const data = "\x1f\x8b\b\x04\x00\tn\x88\x00\xff\a\x00foo bar\xcbH\xcd\xc9\xc9\xd7Q(\xcf/\xcaI\x01\x04:r\xab\xff\f\x00\x00\x00"
+
+       // Intentionally iterate starting with at least one byte in the stream.
+       for i := 1; i < len(data)-1; i++ {
+               r, err := NewReader(strings.NewReader(data[:i]))
+               if err != nil {
+                       if err != io.ErrUnexpectedEOF {
+                               t.Errorf("NewReader(%d) on truncated stream: got %v, want %v", i, err, io.ErrUnexpectedEOF)
+                       }
+                       continue
+               }
+               _, err = io.Copy(ioutil.Discard, r)
+               if ferr, ok := err.(*flate.ReadError); ok {
+                       err = ferr.Err
+               }
+               if err != io.ErrUnexpectedEOF {
+                       t.Errorf("io.Copy(%d) on truncated stream: got %v, want %v", i, err, io.ErrUnexpectedEOF)
+               }
+       }
+}
index 5131d128e4e21e348e975d4180b0207878a164dc..4d945e47fe819d83a1d2bb5cd90b2ffdf8a016de 100644 (file)
@@ -25,7 +25,7 @@ const (
 // A Writer is an io.WriteCloser.
 // Writes to a Writer are compressed and written to w.
 type Writer struct {
-       Header
+       Header      // written at first call to Write, Flush, or Close
        w           io.Writer
        level       int
        wroteHeader bool
@@ -44,10 +44,7 @@ type Writer struct {
 // Writes may be buffered and not flushed until Close.
 //
 // Callers that wish to set the fields in Writer.Header must do so before
-// the first call to Write or Close. The Comment and Name header fields are
-// UTF-8 strings in Go, but the underlying format requires NUL-terminated ISO
-// 8859-1 (Latin-1). NUL or non-Latin-1 runes in those strings will lead to an
-// error on Write.
+// the first call to Write, Flush, or Close.
 func NewWriter(w io.Writer) *Writer {
        z, _ := NewWriterLevel(w, DefaultCompression)
        return z
index 1353831eca9d8ad4d9a243da5f8cfc6cef1ae31c..9eef2b2a782b7c763de77116d14c843747507bc9 100644 (file)
@@ -132,6 +132,7 @@ func (d *decoder) Read(b []byte) (int, error) {
 // litWidth is the width in bits of literal codes.
 func (d *decoder) decode() {
        // Loop over the code stream, converting codes into decompressed bytes.
+loop:
        for {
                code, err := d.read(d)
                if err != nil {
@@ -139,8 +140,7 @@ func (d *decoder) decode() {
                                err = io.ErrUnexpectedEOF
                        }
                        d.err = err
-                       d.flush()
-                       return
+                       break
                }
                switch {
                case code < d.clear:
@@ -159,9 +159,8 @@ func (d *decoder) decode() {
                        d.last = decoderInvalidCode
                        continue
                case code == d.eof:
-                       d.flush()
                        d.err = io.EOF
-                       return
+                       break loop
                case code <= d.hi:
                        c, i := code, len(d.output)-1
                        if code == d.hi {
@@ -191,8 +190,7 @@ func (d *decoder) decode() {
                        }
                default:
                        d.err = errors.New("lzw: invalid code")
-                       d.flush()
-                       return
+                       break loop
                }
                d.last, d.hi = code, d.hi+1
                if d.hi >= d.overflow {
@@ -204,13 +202,10 @@ func (d *decoder) decode() {
                        }
                }
                if d.o >= flushBuffer {
-                       d.flush()
-                       return
+                       break
                }
        }
-}
-
-func (d *decoder) flush() {
+       // Flush pending output.
        d.toRead = d.output[:d.o]
        d.o = 0
 }
index c20d058f8d3df34d2f9abfb839643831539447b6..66d761727f481d81dabf05348d27ee0bddd95bf1 100644 (file)
@@ -5,6 +5,7 @@
 package lzw
 
 import (
+       "internal/testenv"
        "io"
        "io/ioutil"
        "os"
@@ -13,6 +14,7 @@ import (
 )
 
 var filenames = []string{
+       "../testdata/gettysburg.txt",
        "../testdata/e.txt",
        "../testdata/pi.txt",
 }
@@ -89,10 +91,16 @@ func TestWriter(t *testing.T) {
        for _, filename := range filenames {
                for _, order := range [...]Order{LSB, MSB} {
                        // The test data "2.71828 etcetera" is ASCII text requiring at least 6 bits.
-                       for _, litWidth := range [...]int{6, 7, 8} {
+                       for litWidth := 6; litWidth <= 8; litWidth++ {
+                               if filename == "../testdata/gettysburg.txt" && litWidth == 6 {
+                                       continue
+                               }
                                testFile(t, filename, order, litWidth)
                        }
                }
+               if testing.Short() && testenv.Builder() == "" {
+                       break
+               }
        }
 }
 
index c97da7eccf34b333e95a02fa256ba2f4413e03ba..c9106fd522cec80b8de64958de765776a1476488 100644 (file)
@@ -1,27 +1,3 @@
-The Project Gutenberg EBook of The Adventures of Tom Sawyer, Complete
-by Mark Twain (Samuel Clemens)
-
-This eBook is for the use of anyone anywhere at no cost and with
-almost no restrictions whatsoever.  You may copy it, give it away or
-re-use it under the terms of the Project Gutenberg License included
-with this eBook or online at www.gutenberg.net
-
-
-Title: The Adventures of Tom Sawyer, Complete
-
-Author: Mark Twain (Samuel Clemens)
-
-Release Date: August 20, 2006 [EBook #74]
-[Last updated: May 3, 2011]
-
-Language: English
-
-
-*** START OF THIS PROJECT GUTENBERG EBOOK TOM SAWYER ***
-
-
-
-
 Produced by David Widger. The previous edition was updated by Jose
 Menendez.
 
@@ -8487,372 +8463,3 @@ prosperous and happy. Some day it may seem worth while to take up the
 story of the younger ones again and see what sort of men and women they
 turned out to be; therefore it will be wisest not to reveal any of that
 part of their lives at present.
-
-
-
-
-
-End of the Project Gutenberg EBook of The Adventures of Tom Sawyer, Complete
-by Mark Twain (Samuel Clemens)
-
-*** END OF THIS PROJECT GUTENBERG EBOOK TOM SAWYER ***
-
-***** This file should be named 74.txt or 74.zip *****
-This and all associated files of various formats will be found in:
-        http://www.gutenberg.net/7/74/
-
-Produced by David Widger. The previous edition was update by Jose
-Menendez.
-
-
-Updated editions will replace the previous one--the old editions
-will be renamed.
-
-Creating the works from public domain print editions means that no
-one owns a United States copyright in these works, so the Foundation
-(and you!) can copy and distribute it in the United States without
-permission and without paying copyright royalties.  Special rules,
-set forth in the General Terms of Use part of this license, apply to
-copying and distributing Project Gutenberg-tm electronic works to
-protect the PROJECT GUTENBERG-tm concept and trademark.  Project
-Gutenberg is a registered trademark, and may not be used if you
-charge for the eBooks, unless you receive specific permission.  If you
-do not charge anything for copies of this eBook, complying with the
-rules is very easy.  You may use this eBook for nearly any purpose
-such as creation of derivative works, reports, performances and
-research.  They may be modified and printed and given away--you may do
-practically ANYTHING with public domain eBooks.  Redistribution is
-subject to the trademark license, especially commercial
-redistribution.
-
-
-
-*** START: FULL LICENSE ***
-
-THE FULL PROJECT GUTENBERG LICENSE
-PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK
-
-To protect the Project Gutenberg-tm mission of promoting the free
-distribution of electronic works, by using or distributing this work
-(or any other work associated in any way with the phrase "Project
-Gutenberg"), you agree to comply with all the terms of the Full Project
-Gutenberg-tm License (available with this file or online at
-http://gutenberg.net/license).
-
-
-Section 1.  General Terms of Use and Redistributing Project Gutenberg-tm
-electronic works
-
-1.A.  By reading or using any part of this Project Gutenberg-tm
-electronic work, you indicate that you have read, understand, agree to
-and accept all the terms of this license and intellectual property
-(trademark/copyright) agreement.  If you do not agree to abide by all
-the terms of this agreement, you must cease using and return or destroy
-all copies of Project Gutenberg-tm electronic works in your possession.
-If you paid a fee for obtaining a copy of or access to a Project
-Gutenberg-tm electronic work and you do not agree to be bound by the
-terms of this agreement, you may obtain a refund from the person or
-entity to whom you paid the fee as set forth in paragraph 1.E.8.
-
-1.B.  "Project Gutenberg" is a registered trademark.  It may only be
-used on or associated in any way with an electronic work by people who
-agree to be bound by the terms of this agreement.  There are a few
-things that you can do with most Project Gutenberg-tm electronic works
-even without complying with the full terms of this agreement.  See
-paragraph 1.C below.  There are a lot of things you can do with Project
-Gutenberg-tm electronic works if you follow the terms of this agreement
-and help preserve free future access to Project Gutenberg-tm electronic
-works.  See paragraph 1.E below.
-
-1.C.  The Project Gutenberg Literary Archive Foundation ("the Foundation"
-or PGLAF), owns a compilation copyright in the collection of Project
-Gutenberg-tm electronic works.  Nearly all the individual works in the
-collection are in the public domain in the United States.  If an
-individual work is in the public domain in the United States and you are
-located in the United States, we do not claim a right to prevent you from
-copying, distributing, performing, displaying or creating derivative
-works based on the work as long as all references to Project Gutenberg
-are removed.  Of course, we hope that you will support the Project
-Gutenberg-tm mission of promoting free access to electronic works by
-freely sharing Project Gutenberg-tm works in compliance with the terms of
-this agreement for keeping the Project Gutenberg-tm name associated with
-the work.  You can easily comply with the terms of this agreement by
-keeping this work in the same format with its attached full Project
-Gutenberg-tm License when you share it without charge with others.
-
-1.D.  The copyright laws of the place where you are located also govern
-what you can do with this work.  Copyright laws in most countries are in
-a constant state of change.  If you are outside the United States, check
-the laws of your country in addition to the terms of this agreement
-before downloading, copying, displaying, performing, distributing or
-creating derivative works based on this work or any other Project
-Gutenberg-tm work.  The Foundation makes no representations concerning
-the copyright status of any work in any country outside the United
-States.
-
-1.E.  Unless you have removed all references to Project Gutenberg:
-
-1.E.1.  The following sentence, with active links to, or other immediate
-access to, the full Project Gutenberg-tm License must appear prominently
-whenever any copy of a Project Gutenberg-tm work (any work on which the
-phrase "Project Gutenberg" appears, or with which the phrase "Project
-Gutenberg" is associated) is accessed, displayed, performed, viewed,
-copied or distributed:
-
-This eBook is for the use of anyone anywhere at no cost and with
-almost no restrictions whatsoever.  You may copy it, give it away or
-re-use it under the terms of the Project Gutenberg License included
-with this eBook or online at www.gutenberg.net
-
-1.E.2.  If an individual Project Gutenberg-tm electronic work is derived
-from the public domain (does not contain a notice indicating that it is
-posted with permission of the copyright holder), the work can be copied
-and distributed to anyone in the United States without paying any fees
-or charges.  If you are redistributing or providing access to a work
-with the phrase "Project Gutenberg" associated with or appearing on the
-work, you must comply either with the requirements of paragraphs 1.E.1
-through 1.E.7 or obtain permission for the use of the work and the
-Project Gutenberg-tm trademark as set forth in paragraphs 1.E.8 or
-1.E.9.
-
-1.E.3.  If an individual Project Gutenberg-tm electronic work is posted
-with the permission of the copyright holder, your use and distribution
-must comply with both paragraphs 1.E.1 through 1.E.7 and any additional
-terms imposed by the copyright holder.  Additional terms will be linked
-to the Project Gutenberg-tm License for all works posted with the
-permission of the copyright holder found at the beginning of this work.
-
-1.E.4.  Do not unlink or detach or remove the full Project Gutenberg-tm
-License terms from this work, or any files containing a part of this
-work or any other work associated with Project Gutenberg-tm.
-
-1.E.5.  Do not copy, display, perform, distribute or redistribute this
-electronic work, or any part of this electronic work, without
-prominently displaying the sentence set forth in paragraph 1.E.1 with
-active links or immediate access to the full terms of the Project
-Gutenberg-tm License.
-
-1.E.6.  You may convert to and distribute this work in any binary,
-compressed, marked up, nonproprietary or proprietary form, including any
-word processing or hypertext form.  However, if you provide access to or
-distribute copies of a Project Gutenberg-tm work in a format other than
-"Plain Vanilla ASCII" or other format used in the official version
-posted on the official Project Gutenberg-tm web site (www.gutenberg.net),
-you must, at no additional cost, fee or expense to the user, provide a
-copy, a means of exporting a copy, or a means of obtaining a copy upon
-request, of the work in its original "Plain Vanilla ASCII" or other
-form.  Any alternate format must include the full Project Gutenberg-tm
-License as specified in paragraph 1.E.1.
-
-1.E.7.  Do not charge a fee for access to, viewing, displaying,
-performing, copying or distributing any Project Gutenberg-tm works
-unless you comply with paragraph 1.E.8 or 1.E.9.
-
-1.E.8.  You may charge a reasonable fee for copies of or providing
-access to or distributing Project Gutenberg-tm electronic works provided
-that
-
-- You pay a royalty fee of 20% of the gross profits you derive from
-     the use of Project Gutenberg-tm works calculated using the method
-     you already use to calculate your applicable taxes.  The fee is
-     owed to the owner of the Project Gutenberg-tm trademark, but he
-     has agreed to donate royalties under this paragraph to the
-     Project Gutenberg Literary Archive Foundation.  Royalty payments
-     must be paid within 60 days following each date on which you
-     prepare (or are legally required to prepare) your periodic tax
-     returns.  Royalty payments should be clearly marked as such and
-     sent to the Project Gutenberg Literary Archive Foundation at the
-     address specified in Section 4, "Information about donations to
-     the Project Gutenberg Literary Archive Foundation."
-
-- You provide a full refund of any money paid by a user who notifies
-     you in writing (or by e-mail) within 30 days of receipt that s/he
-     does not agree to the terms of the full Project Gutenberg-tm
-     License.  You must require such a user to return or
-     destroy all copies of the works possessed in a physical medium
-     and discontinue all use of and all access to other copies of
-     Project Gutenberg-tm works.
-
-- You provide, in accordance with paragraph 1.F.3, a full refund of any
-     money paid for a work or a replacement copy, if a defect in the
-     electronic work is discovered and reported to you within 90 days
-     of receipt of the work.
-
-- You comply with all other terms of this agreement for free
-     distribution of Project Gutenberg-tm works.
-
-1.E.9.  If you wish to charge a fee or distribute a Project Gutenberg-tm
-electronic work or group of works on different terms than are set
-forth in this agreement, you must obtain permission in writing from
-both the Project Gutenberg Literary Archive Foundation and Michael
-Hart, the owner of the Project Gutenberg-tm trademark.  Contact the
-Foundation as set forth in Section 3 below.
-
-1.F.
-
-1.F.1.  Project Gutenberg volunteers and employees expend considerable
-effort to identify, do copyright research on, transcribe and proofread
-public domain works in creating the Project Gutenberg-tm
-collection.  Despite these efforts, Project Gutenberg-tm electronic
-works, and the medium on which they may be stored, may contain
-"Defects," such as, but not limited to, incomplete, inaccurate or
-corrupt data, transcription errors, a copyright or other intellectual
-property infringement, a defective or damaged disk or other medium, a
-computer virus, or computer codes that damage or cannot be read by
-your equipment.
-
-1.F.2.  LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for the "Right
-of Replacement or Refund" described in paragraph 1.F.3, the Project
-Gutenberg Literary Archive Foundation, the owner of the Project
-Gutenberg-tm trademark, and any other party distributing a Project
-Gutenberg-tm electronic work under this agreement, disclaim all
-liability to you for damages, costs and expenses, including legal
-fees.  YOU AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT
-LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE
-PROVIDED IN PARAGRAPH F3.  YOU AGREE THAT THE FOUNDATION, THE
-TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE
-LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE OR
-INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH
-DAMAGE.
-
-1.F.3.  LIMITED RIGHT OF REPLACEMENT OR REFUND - If you discover a
-defect in this electronic work within 90 days of receiving it, you can
-receive a refund of the money (if any) you paid for it by sending a
-written explanation to the person you received the work from.  If you
-received the work on a physical medium, you must return the medium with
-your written explanation.  The person or entity that provided you with
-the defective work may elect to provide a replacement copy in lieu of a
-refund.  If you received the work electronically, the person or entity
-providing it to you may choose to give you a second opportunity to
-receive the work electronically in lieu of a refund.  If the second copy
-is also defective, you may demand a refund in writing without further
-opportunities to fix the problem.
-
-1.F.4.  Except for the limited right of replacement or refund set forth
-in paragraph 1.F.3, this work is provided to you 'AS-IS' WITH NO OTHER
-WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
-WARRANTIES OF MERCHANTIBILITY OR FITNESS FOR ANY PURPOSE.
-
-1.F.5.  Some states do not allow disclaimers of certain implied
-warranties or the exclusion or limitation of certain types of damages.
-If any disclaimer or limitation set forth in this agreement violates the
-law of the state applicable to this agreement, the agreement shall be
-interpreted to make the maximum disclaimer or limitation permitted by
-the applicable state law.  The invalidity or unenforceability of any
-provision of this agreement shall not void the remaining provisions.
-
-1.F.6.  INDEMNITY - You agree to indemnify and hold the Foundation, the
-trademark owner, any agent or employee of the Foundation, anyone
-providing copies of Project Gutenberg-tm electronic works in accordance
-with this agreement, and any volunteers associated with the production,
-promotion and distribution of Project Gutenberg-tm electronic works,
-harmless from all liability, costs and expenses, including legal fees,
-that arise directly or indirectly from any of the following which you do
-or cause to occur: (a) distribution of this or any Project Gutenberg-tm
-work, (b) alteration, modification, or additions or deletions to any
-Project Gutenberg-tm work, and (c) any Defect you cause.
-
-
-Section  2.  Information about the Mission of Project Gutenberg-tm
-
-Project Gutenberg-tm is synonymous with the free distribution of
-electronic works in formats readable by the widest variety of computers
-including obsolete, old, middle-aged and new computers.  It exists
-because of the efforts of hundreds of volunteers and donations from
-people in all walks of life.
-
-Volunteers and financial support to provide volunteers with the
-assistance they need, is critical to reaching Project Gutenberg-tm's
-goals and ensuring that the Project Gutenberg-tm collection will
-remain freely available for generations to come.  In 2001, the Project
-Gutenberg Literary Archive Foundation was created to provide a secure
-and permanent future for Project Gutenberg-tm and future generations.
-To learn more about the Project Gutenberg Literary Archive Foundation
-and how your efforts and donations can help, see Sections 3 and 4
-and the Foundation web page at http://www.pglaf.org.
-
-
-Section 3.  Information about the Project Gutenberg Literary Archive
-Foundation
-
-The Project Gutenberg Literary Archive Foundation is a non profit
-501(c)(3) educational corporation organized under the laws of the
-state of Mississippi and granted tax exempt status by the Internal
-Revenue Service.  The Foundation's EIN or federal tax identification
-number is 64-6221541.  Its 501(c)(3) letter is posted at
-http://pglaf.org/fundraising.  Contributions to the Project Gutenberg
-Literary Archive Foundation are tax deductible to the full extent
-permitted by U.S. federal laws and your state's laws.
-
-The Foundation's principal office is located at 4557 Melan Dr. S.
-Fairbanks, AK, 99712., but its volunteers and employees are scattered
-throughout numerous locations.  Its business office is located at
-809 North 1500 West, Salt Lake City, UT 84116, (801) 596-1887, email
-business@pglaf.org.  Email contact links and up to date contact
-information can be found at the Foundation's web site and official
-page at http://pglaf.org
-
-For additional contact information:
-     Dr. Gregory B. Newby
-     Chief Executive and Director
-     gbnewby@pglaf.org
-
-
-Section 4.  Information about Donations to the Project Gutenberg
-Literary Archive Foundation
-
-Project Gutenberg-tm depends upon and cannot survive without wide
-spread public support and donations to carry out its mission of
-increasing the number of public domain and licensed works that can be
-freely distributed in machine readable form accessible by the widest
-array of equipment including outdated equipment.  Many small donations
-($1 to $5,000) are particularly important to maintaining tax exempt
-status with the IRS.
-
-The Foundation is committed to complying with the laws regulating
-charities and charitable donations in all 50 states of the United
-States.  Compliance requirements are not uniform and it takes a
-considerable effort, much paperwork and many fees to meet and keep up
-with these requirements.  We do not solicit donations in locations
-where we have not received written confirmation of compliance.  To
-SEND DONATIONS or determine the status of compliance for any
-particular state visit http://pglaf.org
-
-While we cannot and do not solicit contributions from states where we
-have not met the solicitation requirements, we know of no prohibition
-against accepting unsolicited donations from donors in such states who
-approach us with offers to donate.
-
-International donations are gratefully accepted, but we cannot make
-any statements concerning tax treatment of donations received from
-outside the United States.  U.S. laws alone swamp our small staff.
-
-Please check the Project Gutenberg Web pages for current donation
-methods and addresses.  Donations are accepted in a number of other
-ways including including checks, online payments and credit card
-donations.  To donate, please visit: http://pglaf.org/donate
-
-
-Section 5.  General Information About Project Gutenberg-tm electronic
-works.
-
-Professor Michael S. Hart is the originator of the Project Gutenberg-tm
-concept of a library of electronic works that could be freely shared
-with anyone.  For thirty years, he produced and distributed Project
-Gutenberg-tm eBooks with only a loose network of volunteer support.
-
-
-Project Gutenberg-tm eBooks are often created from several printed
-editions, all of which are confirmed as Public Domain in the U.S.
-unless a copyright notice is included.  Thus, we do not necessarily
-keep eBooks in compliance with any particular paper edition.
-
-
-Most people start at our Web site which has the main PG search facility:
-
-     http://www.gutenberg.net
-
-This Web site includes information about Project Gutenberg-tm,
-including how to make donations to the Project Gutenberg Literary
-Archive Foundation, how to help produce our new eBooks, and how to
-subscribe to our email newsletter to hear about new eBooks.
diff --git a/libgo/go/compress/testdata/gettysburg.txt b/libgo/go/compress/testdata/gettysburg.txt
new file mode 100644 (file)
index 0000000..2c9bcde
--- /dev/null
@@ -0,0 +1,29 @@
+  Four score and seven years ago our fathers brought forth on
+this continent, a new nation, conceived in Liberty, and dedicated
+to the proposition that all men are created equal.
+  Now we are engaged in a great Civil War, testing whether that
+nation, or any nation so conceived and so dedicated, can long
+endure.
+  We are met on a great battle-field of that war.
+  We have come to dedicate a portion of that field, as a final
+resting place for those who here gave their lives that that
+nation might live.  It is altogether fitting and proper that
+we should do this.
+  But, in a larger sense, we can not dedicate - we can not
+consecrate - we can not hallow - this ground.
+  The brave men, living and dead, who struggled here, have
+consecrated it, far above our poor power to add or detract.
+The world will little note, nor long remember what we say here,
+but it can never forget what they did here.
+  It is for us the living, rather, to be dedicated here to the
+unfinished work which they who fought here have thus far so
+nobly advanced.  It is rather for us to be here dedicated to
+the great task remaining before us - that from these honored
+dead we take increased devotion to that cause for which they
+gave the last full measure of devotion -
+  that we here highly resolve that these dead shall not have
+died in vain - that this nation, under God, shall have a new
+birth of freedom - and that government of the people, by the
+people, for the people, shall not perish from this earth.
+
+Abraham Lincoln, November 19, 1863, Gettysburg, Pennsylvania
index 816f1bf6bd06e73dd24b781a2af8839fb08e25b9..78ea7043bcee353987e41b8ca210634247b75ad9 100644 (file)
@@ -101,6 +101,9 @@ func (z *reader) Read(p []byte) (n int, err error) {
 
        // Finished file; check checksum.
        if _, err := io.ReadFull(z.r, z.scratch[0:4]); err != nil {
+               if err == io.EOF {
+                       err = io.ErrUnexpectedEOF
+               }
                z.err = err
                return 0, err
        }
@@ -130,6 +133,9 @@ func (z *reader) Reset(r io.Reader, dict []byte) error {
        }
        _, err := io.ReadFull(z.r, z.scratch[0:2])
        if err != nil {
+               if err == io.EOF {
+                       err = io.ErrUnexpectedEOF
+               }
                return err
        }
        h := uint(z.scratch[0])<<8 | uint(z.scratch[1])
@@ -140,6 +146,9 @@ func (z *reader) Reset(r io.Reader, dict []byte) error {
        if haveDict {
                _, err = io.ReadFull(z.r, z.scratch[0:4])
                if err != nil {
+                       if err == io.EOF {
+                               err = io.ErrUnexpectedEOF
+                       }
                        return err
                }
                checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
index 218ccba14110fcdcd0a64a778891c377d454284b..449f4460bcd3baa0d9b98b7c4f32b974b85b3d86 100644 (file)
@@ -22,6 +22,30 @@ type zlibTest struct {
 // http://www.zlib.net/zpipe.c
 
 var zlibTests = []zlibTest{
+       {
+               "truncated empty",
+               "",
+               []byte{},
+               nil,
+               io.ErrUnexpectedEOF,
+       },
+       {
+               "truncated dict",
+               "",
+               []byte{0x78, 0xbb},
+               []byte{0x00},
+               io.ErrUnexpectedEOF,
+       },
+       {
+               "truncated checksum",
+               "",
+               []byte{0x78, 0xbb, 0x00, 0x01, 0x00, 0x01, 0xca, 0x48,
+                       0xcd, 0xc9, 0xc9, 0xd7, 0x51, 0x28, 0xcf, 0x2f,
+                       0xca, 0x49, 0x01, 0x04, 0x00, 0x00, 0xff, 0xff,
+               },
+               []byte{0x00},
+               io.ErrUnexpectedEOF,
+       },
        {
                "empty",
                "",
index 71ba81aaa764b5a471ae06a9b903692b4f3c1a1f..dd941655206efa36d3b6b5be6b749e64676b04c6 100644 (file)
@@ -7,6 +7,7 @@ package zlib
 import (
        "bytes"
        "fmt"
+       "internal/testenv"
        "io"
        "io/ioutil"
        "os"
@@ -14,6 +15,7 @@ import (
 )
 
 var filenames = []string{
+       "../testdata/gettysburg.txt",
        "../testdata/e.txt",
        "../testdata/pi.txt",
 }
@@ -152,22 +154,34 @@ func TestWriter(t *testing.T) {
 }
 
 func TestWriterBig(t *testing.T) {
-       for _, fn := range filenames {
+       for i, fn := range filenames {
                testFileLevelDict(t, fn, DefaultCompression, "")
                testFileLevelDict(t, fn, NoCompression, "")
                for level := BestSpeed; level <= BestCompression; level++ {
                        testFileLevelDict(t, fn, level, "")
+                       if level >= 1 && testing.Short() && testenv.Builder() == "" {
+                               break
+                       }
+               }
+               if i == 0 && testing.Short() && testenv.Builder() == "" {
+                       break
                }
        }
 }
 
 func TestWriterDict(t *testing.T) {
        const dictionary = "0123456789."
-       for _, fn := range filenames {
+       for i, fn := range filenames {
                testFileLevelDict(t, fn, DefaultCompression, dictionary)
                testFileLevelDict(t, fn, NoCompression, dictionary)
                for level := BestSpeed; level <= BestCompression; level++ {
                        testFileLevelDict(t, fn, level, dictionary)
+                       if level >= 1 && testing.Short() && testenv.Builder() == "" {
+                               break
+                       }
+               }
+               if i == 0 && testing.Short() && testenv.Builder() == "" {
+                       break
                }
        }
 }
@@ -179,10 +193,11 @@ func TestWriterReset(t *testing.T) {
                testFileLevelDictReset(t, fn, DefaultCompression, nil)
                testFileLevelDictReset(t, fn, NoCompression, []byte(dictionary))
                testFileLevelDictReset(t, fn, DefaultCompression, []byte(dictionary))
-               if !testing.Short() {
-                       for level := BestSpeed; level <= BestCompression; level++ {
-                               testFileLevelDictReset(t, fn, level, nil)
-                       }
+               if testing.Short() {
+                       break
+               }
+               for level := BestSpeed; level <= BestCompression; level++ {
+                       testFileLevelDictReset(t, fn, level, nil)
                }
        }
 }
diff --git a/libgo/go/crypto/aes/aes_gcm.go b/libgo/go/crypto/aes/aes_gcm.go
new file mode 100644 (file)
index 0000000..1377578
--- /dev/null
@@ -0,0 +1,172 @@
+// Copyright 2015 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 amd64
+
+package aes
+
+import (
+       "crypto/cipher"
+       "crypto/subtle"
+       "errors"
+)
+
+// The following functions are defined in gcm_amd64.s.
+func hasGCMAsm() bool
+
+//go:noescape
+func aesEncBlock(dst, src *[16]byte, ks []uint32)
+
+//go:noescape
+func gcmAesInit(productTable *[256]byte, ks []uint32)
+
+//go:noescape
+func gcmAesData(productTable *[256]byte, data []byte, T *[16]byte)
+
+//go:noescape
+func gcmAesEnc(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32)
+
+//go:noescape
+func gcmAesDec(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32)
+
+//go:noescape
+func gcmAesFinish(productTable *[256]byte, tagMask, T *[16]byte, pLen, dLen uint64)
+
+const (
+       gcmBlockSize         = 16
+       gcmTagSize           = 16
+       gcmStandardNonceSize = 12
+)
+
+var errOpen = errors.New("cipher: message authentication failed")
+
+// aesCipherGCM implements crypto/cipher.gcmAble so that crypto/cipher.NewGCM
+// will use the optimised implementation in this file when possible. Instances
+// of this type only exist when hasGCMAsm returns true.
+type aesCipherGCM struct {
+       aesCipher
+}
+
+// NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only
+// called by crypto/cipher.NewGCM via the gcmAble interface.
+func (c *aesCipherGCM) NewGCM(nonceSize int) (cipher.AEAD, error) {
+       g := &gcmAsm{ks: c.enc, nonceSize: nonceSize}
+       gcmAesInit(&g.productTable, g.ks)
+       return g, nil
+}
+
+type gcmAsm struct {
+       // ks is the key schedule, the length of which depends on the size of
+       // the AES key.
+       ks []uint32
+       // productTable contains pre-computed multiples of the binary-field
+       // element used in GHASH.
+       productTable [256]byte
+       // nonceSize contains the expected size of the nonce, in bytes.
+       nonceSize int
+}
+
+func (g *gcmAsm) NonceSize() int {
+       return g.nonceSize
+}
+
+func (*gcmAsm) Overhead() int {
+       return gcmTagSize
+}
+
+// sliceForAppend takes a slice and a requested number of bytes. It returns a
+// slice with the contents of the given slice followed by that many bytes and a
+// second slice that aliases into it and contains only the extra bytes. If the
+// original slice has sufficient capacity then no allocation is performed.
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+       if total := len(in) + n; cap(in) >= total {
+               head = in[:total]
+       } else {
+               head = make([]byte, total)
+               copy(head, in)
+       }
+       tail = head[len(in):]
+       return
+}
+
+// Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for
+// details.
+func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
+       if len(nonce) != g.nonceSize {
+               panic("cipher: incorrect nonce length given to GCM")
+       }
+
+       var counter, tagMask [gcmBlockSize]byte
+
+       if len(nonce) == gcmStandardNonceSize {
+               // Init counter to nonce||1
+               copy(counter[:], nonce)
+               counter[gcmBlockSize-1] = 1
+       } else {
+               // Otherwise counter = GHASH(nonce)
+               gcmAesData(&g.productTable, nonce, &counter)
+               gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
+       }
+
+       aesEncBlock(&tagMask, &counter, g.ks)
+
+       var tagOut [gcmTagSize]byte
+       gcmAesData(&g.productTable, data, &tagOut)
+
+       ret, out := sliceForAppend(dst, len(plaintext)+gcmTagSize)
+       if len(plaintext) > 0 {
+               gcmAesEnc(&g.productTable, out, plaintext, &counter, &tagOut, g.ks)
+       }
+       gcmAesFinish(&g.productTable, &tagMask, &tagOut, uint64(len(plaintext)), uint64(len(data)))
+       copy(out[len(plaintext):], tagOut[:])
+
+       return ret
+}
+
+// Open authenticates and decrypts ciphertext. See the cipher.AEAD interface
+// for details.
+func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
+       if len(nonce) != g.nonceSize {
+               panic("cipher: incorrect nonce length given to GCM")
+       }
+
+       if len(ciphertext) < gcmTagSize {
+               return nil, errOpen
+       }
+       tag := ciphertext[len(ciphertext)-gcmTagSize:]
+       ciphertext = ciphertext[:len(ciphertext)-gcmTagSize]
+
+       // See GCM spec, section 7.1.
+       var counter, tagMask [gcmBlockSize]byte
+
+       if len(nonce) == gcmStandardNonceSize {
+               // Init counter to nonce||1
+               copy(counter[:], nonce)
+               counter[gcmBlockSize-1] = 1
+       } else {
+               // Otherwise counter = GHASH(nonce)
+               gcmAesData(&g.productTable, nonce, &counter)
+               gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
+       }
+
+       aesEncBlock(&tagMask, &counter, g.ks)
+
+       var expectedTag [gcmTagSize]byte
+       gcmAesData(&g.productTable, data, &expectedTag)
+
+       ret, out := sliceForAppend(dst, len(ciphertext))
+       if len(ciphertext) > 0 {
+               gcmAesDec(&g.productTable, out, ciphertext, &counter, &expectedTag, g.ks)
+       }
+       gcmAesFinish(&g.productTable, &tagMask, &expectedTag, uint64(len(ciphertext)), uint64(len(data)))
+
+       if subtle.ConstantTimeCompare(expectedTag[:], tag) != 1 {
+               for i := range out {
+                       out[i] = 0
+               }
+               return nil, errOpen
+       }
+
+       return ret, nil
+}
index 2c6bb0a89c7b753359f862081c0f858879b7c99b..04d2be1283fb8566199d68d616446d67205283c0 100644 (file)
@@ -38,9 +38,14 @@ func NewCipher(key []byte) (cipher.Block, error) {
        }
 
        n := k + 28
-       c := &aesCipher{make([]uint32, n), make([]uint32, n)}
+       c := aesCipher{make([]uint32, n), make([]uint32, n)}
        expandKey(key, c.enc, c.dec)
-       return c, nil
+
+       if hasGCMAsm() {
+               return &aesCipherGCM{c}, nil
+       }
+
+       return &c, nil
 }
 
 func (c *aesCipher) BlockSize() int { return BlockSize }
index 1714e0f1e5cbdba4d890998e9f0f6bc9388ac5fe..32b2b3cc56d67b54a6cbcaf30aaaf1615e6af319 100644 (file)
@@ -17,3 +17,11 @@ func decryptBlock(xk []uint32, dst, src []byte) {
 func expandKey(key []byte, enc, dec []uint32) {
        expandKeyGo(key, enc, dec)
 }
+
+func hasGCMAsm() bool {
+       return false
+}
+
+type aesCipherGCM struct {
+       aesCipher
+}
index 027b24851055080af962b010609e510d7c7c8b36..93c40d0f4665fe50688fcb8dc07b7476a794da71 100644 (file)
@@ -10,42 +10,58 @@ import (
        "testing"
 )
 
-func BenchmarkAESGCMSeal1K(b *testing.B) {
-       buf := make([]byte, 1024)
+func benchmarkAESGCMSeal(b *testing.B, buf []byte) {
        b.SetBytes(int64(len(buf)))
 
        var key [16]byte
        var nonce [12]byte
+       var ad [13]byte
        aes, _ := aes.NewCipher(key[:])
        aesgcm, _ := cipher.NewGCM(aes)
        var out []byte
 
        b.ResetTimer()
        for i := 0; i < b.N; i++ {
-               out = aesgcm.Seal(out[:0], nonce[:], buf, nonce[:])
+               out = aesgcm.Seal(out[:0], nonce[:], buf, ad[:])
        }
 }
 
-func BenchmarkAESGCMOpen1K(b *testing.B) {
-       buf := make([]byte, 1024)
+func benchmarkAESGCMOpen(b *testing.B, buf []byte) {
        b.SetBytes(int64(len(buf)))
 
        var key [16]byte
        var nonce [12]byte
+       var ad [13]byte
        aes, _ := aes.NewCipher(key[:])
        aesgcm, _ := cipher.NewGCM(aes)
        var out []byte
-       out = aesgcm.Seal(out[:0], nonce[:], buf, nonce[:])
+       out = aesgcm.Seal(out[:0], nonce[:], buf, ad[:])
 
        b.ResetTimer()
        for i := 0; i < b.N; i++ {
-               _, err := aesgcm.Open(buf[:0], nonce[:], out, nonce[:])
+               _, err := aesgcm.Open(buf[:0], nonce[:], out, ad[:])
                if err != nil {
                        b.Errorf("Open: %v", err)
                }
        }
 }
 
+func BenchmarkAESGCMSeal1K(b *testing.B) {
+       benchmarkAESGCMSeal(b, make([]byte, 1024))
+}
+
+func BenchmarkAESGCMOpen1K(b *testing.B) {
+       benchmarkAESGCMOpen(b, make([]byte, 1024))
+}
+
+func BenchmarkAESGCMSeal8K(b *testing.B) {
+       benchmarkAESGCMSeal(b, make([]byte, 8*1024))
+}
+
+func BenchmarkAESGCMOpen8K(b *testing.B) {
+       benchmarkAESGCMOpen(b, make([]byte, 8*1024))
+}
+
 // If we test exactly 1K blocks, we would generate exact multiples of
 // the cipher's block size, and the cipher stream fragments would
 // always be wordsize aligned, whereas non-aligned is a more typical
index 70ac40f6a7afbd32d58658bd57120c3bc685c899..16baa6d17d0095389f4c50189e01d9a147be7d67 100644 (file)
@@ -41,13 +41,10 @@ func NewCTR(block Block, iv []byte) Stream {
 
 func (x *ctr) refill() {
        remain := len(x.out) - x.outUsed
-       if remain > x.outUsed {
-               return
-       }
        copy(x.out, x.out[x.outUsed:])
        x.out = x.out[:cap(x.out)]
        bs := x.b.BlockSize()
-       for remain < len(x.out)-bs {
+       for remain <= len(x.out)-bs {
                x.b.Encrypt(x.out[remain:], x.ctr)
                remain += bs
 
diff --git a/libgo/go/crypto/cipher/ctr_test.go b/libgo/go/crypto/cipher/ctr_test.go
new file mode 100644 (file)
index 0000000..e5cce57
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright 2015 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 cipher_test
+
+import (
+       "bytes"
+       "crypto/cipher"
+       "testing"
+)
+
+type noopBlock int
+
+func (b noopBlock) BlockSize() int        { return int(b) }
+func (noopBlock) Encrypt(dst, src []byte) { copy(dst, src) }
+func (noopBlock) Decrypt(dst, src []byte) { copy(dst, src) }
+
+func inc(b []byte) {
+       for i := len(b) - 1; i >= 0; i++ {
+               b[i]++
+               if b[i] != 0 {
+                       break
+               }
+       }
+}
+
+func xor(a, b []byte) {
+       for i := range a {
+               a[i] ^= b[i]
+       }
+}
+
+func TestCTR(t *testing.T) {
+       for size := 64; size <= 1024; size *= 2 {
+               iv := make([]byte, size)
+               ctr := cipher.NewCTR(noopBlock(size), iv)
+               src := make([]byte, 1024)
+               for i := range src {
+                       src[i] = 0xff
+               }
+               want := make([]byte, 1024)
+               copy(want, src)
+               counter := make([]byte, size)
+               for i := 1; i < len(want)/size; i++ {
+                       inc(counter)
+                       xor(want[i*size:(i+1)*size], counter)
+               }
+               dst := make([]byte, 1024)
+               ctr.XORKeyStream(dst, src)
+               if !bytes.Equal(dst, want) {
+                       t.Errorf("for size %d\nhave %x\nwant %x", size, dst, want)
+               }
+       }
+}
index 1cfa982df4ba4d7de1fa2db172078002ed64a6dc..f6cc38650610ad23fa474df2a913eabbb5ef106e 100644 (file)
@@ -14,6 +14,58 @@ import (
        "os"
 )
 
+func ExampleNewGCMEncrypter() {
+       // The key argument should be the AES key, either 16 or 32 bytes
+       // to select AES-128 or AES-256.
+       key := []byte("AES256Key-32Characters1234567890")
+       plaintext := []byte("exampleplaintext")
+
+       block, err := aes.NewCipher(key)
+       if err != nil {
+               panic(err.Error())
+       }
+
+       // Never use more than 2^32 random nonces with a given key because of the risk of a repeat.
+       nonce := make([]byte, 12)
+       if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
+               panic(err.Error())
+       }
+
+       aesgcm, err := cipher.NewGCM(block)
+       if err != nil {
+               panic(err.Error())
+       }
+
+       ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil)
+       fmt.Printf("%x\n", ciphertext)
+}
+
+func ExampleNewGCMDecrypter() {
+       // The key argument should be the AES key, either 16 or 32 bytes
+       // to select AES-128 or AES-256.
+       key := []byte("AES256Key-32Characters1234567890")
+       ciphertext, _ := hex.DecodeString("f90fbef747e7212ad7410d0eee2d965de7e890471695cddd2a5bc0ef5da1d04ad8147b62141ad6e4914aee8c512f64fba9037603d41de0d50b718bd665f019cdcd")
+
+       nonce, _ := hex.DecodeString("bb8ef84243d2ee95a41c6c57")
+
+       block, err := aes.NewCipher(key)
+       if err != nil {
+               panic(err.Error())
+       }
+
+       aesgcm, err := cipher.NewGCM(block)
+       if err != nil {
+               panic(err.Error())
+       }
+
+       plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil)
+       if err != nil {
+               panic(err.Error())
+       }
+
+       fmt.Printf("%s\n", string(plaintext))
+}
+
 func ExampleNewCBCDecrypter() {
        key := []byte("example key 1234")
        ciphertext, _ := hex.DecodeString("f363f3ccdcb12bb883abf484ba77d9cd7d32b5baecb3d4b1b3e0e4beffdb3ded")
index bbdf9f5d3df7eb9da5a97c0330f55b2486de8c1e..3868d7123a1d9eacf1455dac2b253b7071118a9f 100644 (file)
@@ -10,14 +10,15 @@ import (
 )
 
 // AEAD is a cipher mode providing authenticated encryption with associated
-// data.
+// data. For a description of the methodology, see
+//     https://en.wikipedia.org/wiki/Authenticated_encryption
 type AEAD interface {
        // NonceSize returns the size of the nonce that must be passed to Seal
        // and Open.
        NonceSize() int
 
        // Overhead returns the maximum difference between the lengths of a
-       // plaintext and ciphertext.
+       // plaintext and its ciphertext.
        Overhead() int
 
        // Seal encrypts and authenticates plaintext, authenticates the
@@ -25,8 +26,9 @@ type AEAD interface {
        // slice. The nonce must be NonceSize() bytes long and unique for all
        // time, for a given key.
        //
-       // The plaintext and dst may alias exactly or not at all.
-       Seal(dst, nonce, plaintext, data []byte) []byte
+       // The plaintext and dst may alias exactly or not at all. To reuse
+       // plaintext's storage for the encrypted output, use plaintext[:0] as dst.
+       Seal(dst, nonce, plaintext, additionalData []byte) []byte
 
        // Open decrypts and authenticates ciphertext, authenticates the
        // additional data and, if successful, appends the resulting plaintext
@@ -34,8 +36,19 @@ type AEAD interface {
        // 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)
+       // The ciphertext and dst may alias exactly or not at all. To reuse
+       // ciphertext's storage for the decrypted output, use ciphertext[:0] as dst.
+       //
+       // Even if the function fails, the contents of dst, up to its capacity,
+       // may be overwritten.
+       Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error)
+}
+
+// gcmAble is an interface implemented by ciphers that have a specific optimized
+// implementation of GCM, like crypto/aes. NewGCM will check for this interface
+// and return the specific AEAD if found.
+type gcmAble interface {
+       NewGCM(int) (AEAD, error)
 }
 
 // gcmFieldElement represents a value in GF(2¹²⁸). In order to reflect the GCM
@@ -72,6 +85,10 @@ func NewGCM(cipher Block) (AEAD, error) {
 // cryptosystem that uses non-standard nonce lengths. All other users should use
 // NewGCM, which is faster and more resistant to misuse.
 func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) {
+       if cipher, ok := cipher.(gcmAble); ok {
+               return cipher.NewGCM(size)
+       }
+
        if cipher.BlockSize() != gcmBlockSize {
                return nil, errors.New("cipher: NewGCM requires 128-bit block cipher")
        }
@@ -154,11 +171,19 @@ func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
        var expectedTag [gcmTagSize]byte
        g.auth(expectedTag[:], ciphertext, data, &tagMask)
 
+       ret, out := sliceForAppend(dst, len(ciphertext))
+
        if subtle.ConstantTimeCompare(expectedTag[:], tag) != 1 {
+               // The AESNI code decrypts and authenticates concurrently, and
+               // so overwrites dst in the event of a tag mismatch. That
+               // behaviour is mimicked here in order to be consistent across
+               // platforms.
+               for i := range out {
+                       out[i] = 0
+               }
                return nil, errOpen
        }
 
-       ret, out := sliceForAppend(dst, len(ciphertext))
        g.counterCrypt(out, ciphertext, &counter)
 
        return ret, nil
index 81b9aa241912f76fc93d7d9194f5466c4acadfb2..bb1ab3c0b0f27e0d976f5dab6c23bd13875e1a28 100644 (file)
@@ -12,8 +12,6 @@ import (
        "testing"
 )
 
-// AES-GCM test vectors taken from gcmEncryptExtIV128.rsp from
-// http://csrc.nist.gov/groups/STM/cavp/index.html.
 var aesGCMTests = []struct {
        key, nonce, plaintext, ad, result string
 }{
@@ -31,6 +29,27 @@ var aesGCMTests = []struct {
                "",
                "60d20404af527d248d893ae495707d1a",
        },
+       {
+               "fbe3467cc254f81be8e78d765a2e6333",
+               "c6697351ff4aec29cdbaabf2",
+               "",
+               "67",
+               "3659cdc25288bf499ac736c03bfc1159",
+       },
+       {
+               "8a7f9d80d08ad0bd5a20fb689c88f9fc",
+               "88b7b27d800937fda4f47301",
+               "",
+               "50edd0503e0d7b8c91608eb5a1",
+               "ed6f65322a4740011f91d2aae22dd44e",
+       },
+       {
+               "051758e95ed4abb2cdc69bb454110e82",
+               "c99a66320db73158a35a255d",
+               "",
+               "67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339f",
+               "6ce77f1a5616c505b6aec09420234036",
+       },
        {
                "77be63708971c4e240d1cb79e8d77feb",
                "e0e00f19fed7ba0136a797f3",
@@ -130,6 +149,41 @@ var aesGCMTests = []struct {
                "8d8c7ffc55086d539b5a8f0d1232654c",
                "0d803ec309482f35b8e6226f2b56303239298e06b281c2d51aaba3c125",
        },
+       {
+               "0e18a844ac5bf38e4cd72d9b0942e506",
+               "0870d4b28a2954489a0abcd5",
+               "67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32af3c54ec18db5c021afe43fbfaaa3afb29d1e6053c7c9475d8be6189f95cbba8990f95b1ebf1b3",
+               "05eff700e9a13ae5ca0bcbd0484764bd1f231ea81c7b64c514735ac55e4b79633b706424119e09dcaad4acf21b10af3b33cde3504847155cbb6f2219ba9b7df50be11a1c7f23f829f8a41b13b5ca4ee8983238e0794d3d34bc5f4e77facb6c05ac86212baa1a55a2be70b5733b045cd33694b3afe2f0e49e4f321549fd824ea9",
+               "cace28f4976afd72e3c5128167eb788fbf6634dda0a2f53148d00f6fa557f5e9e8f736c12e450894af56cb67f7d99e1027258c8571bd91ee3b7360e0d508aa1f382411a16115f9c05251cc326d4016f62e0eb8151c048465b0c6c8ff12558d43310e18b2cb1889eec91557ce21ba05955cf4c1d4847aadfb1b0a83f3a3b82b7efa62a5f03c5d6eda381a85dd78dbc55c",
+       },
+       {
+               "1f6c3a3bc0542aabba4ef8f6c7169e73",
+               "f3584606472b260e0dd2ebb2",
+               "67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32af3c54ec18db5c021afe43fbfaaa3afb29d1e6053c7c9475d8be6189f95cbba8990f95b1ebf1b305eff700e9a13ae5ca0bcbd0484764bd1f231ea81c7b64c514735ac55e4b79633b706424119e09dcaad4acf21b10af3b33cde3504847155cbb6f2219ba9b7df50be11a1c7f23f829f8a41b13b5ca4ee8983238e0794d3d34bc5f4e77facb6c05ac86212baa1a55a2be70b5733b045cd33694b3afe2f0e49e4f321549fd824ea90870d4b28a2954489a0abcd50e18a844ac5bf38e4cd72d9b0942e506c433afcda3847f2dadd47647de321cec4ac430f62023856cfbb20704f4ec0bb920ba86c33e05f1ecd96733b79950a3e314d3d934f75ea0f210a8f6059401beb4bc4478fa4969e623d01ada696a7e4c7e5125b34884533a94fb319990325744ee9bbce9e525cf08f5e9e25e5360aad2b2d085fa54d835e8d466826498d9a8877565705a8a3f62802944de7ca5894e5759d351adac869580ec17e485f18c0c66f17cc07cbb22fce466da610b63af62bc83b4692f3affaf271693ac071fb86d11342d8def4f89d4b66335c1c7e4248367d8ed9612ec453902d8e50af89d7709d1a596c1f41f",
+               "95aa82ca6c49ae90cd1668baac7aa6f2b4a8ca99b2c2372acb08cf61c9c3805e6e0328da4cd76a19edd2d3994c798b0022569ad418d1fee4d9cd45a391c601ffc92ad91501432fee150287617c13629e69fc7281cd7165a63eab49cf714bce3a75a74f76ea7e64ff81eb61fdfec39b67bf0de98c7e4e32bdf97c8c6ac75ba43c02f4b2ed7216ecf3014df000108b67cf99505b179f8ed4980a6103d1bca70dbe9bbfab0ed59801d6e5f2d6f67d3ec5168e212e2daf02c6b963c98a1f7097de0c56891a2b211b01070dd8fd8b16c2a1a4e3cfd292d2984b3561d555d16c33ddc2bcf7edde13efe520c7e2abdda44d81881c531aeeeb66244c3b791ea8acfb6a68",
+               "55864065117e07650ca650a0f0d9ef4b02aee7c58928462fddb49045bf85355b4653fa26158210a7f3ef5b3ca48612e8b7adf5c025c1b821960af770d935df1c9a1dd25077d6b1c7f937b2e20ce981b07980880214698f3fad72fa370b3b7da257ce1d0cf352bc5304fada3e0f8927bd4e5c1abbffa563bdedcb567daa64faaed748cb361732200ba3506836a3c1c82aafa14c76dc07f6c4277ff2c61325f91fdbd6c1883e745fcaadd5a6d692eeaa5ad56eead6a9d74a595d22757ed89532a4b8831e2b9e2315baea70a9b95d228f09d491a5ed5ab7076766703457e3159bbb9b17b329525669863153079448c68cd2f200c0be9d43061a60639cb59d50993d276c05caaa565db8ce633b2673e4012bebbca02b1a64d779d04066f3e949ece173825885ec816468c819a8129007cc05d8785c48077d09eb1abcba14508dde85a6f16a744bc95faef24888d53a8020515ab20307efaecbdf143a26563c67989bceedc2d6d2bb9699bb6c615d93767e4158c1124e3b6c723aaa47796e59a60d3696cd85adfae9a62f2c02c22009f80ed494bdc587f31dd892c253b5c6d6b7db078fa72d23474ee54f8144d6561182d71c862941dbc0b2cb37a4d4b23cbad5637e6be901cc73f16d5aec39c60dddee631511e57b47520b61ae1892d2d1bd2b486e30faec892f171b6de98d96108016fac805604761f8e74742b3bb7dc8a290a46bf697c3e4446e6e65832cbae7cf1aaad1",
+       },
+       {
+               "0795d80bc7f40f4d41c280271a2e4f7f",
+               "ff824c906594aff365d3cb1f",
+               "1ad4e74d127f935beee57cff920665babe7ce56227377afe570ba786193ded3412d4812453157f42fafc418c02a746c1232c234a639d49baa8f041c12e2ef540027764568ce49886e0d913e28059a3a485c6eee96337a30b28e4cd5612c2961539fa6bc5de034cbedc5fa15db844013e0bef276e27ca7a4faf47a5c1093bd643354108144454d221b3737e6cb87faac36ed131959babe44af2890cfcc4e23ffa24470e689ce0894f5407bb0c8665cff536008ad2ac6f1c9ef8289abd0bd9b72f21c597bda5210cf928c805af2dd4a464d52e36819d521f967bba5386930ab5b4cf4c71746d7e6e964673457348e9d71d170d9eb560bd4bdb779e610ba816bf776231ebd0af5966f5cdab6815944032ab4dd060ad8dab880549e910f1ffcf6862005432afad",
+               "98a47a430d8fd74dc1829a91e3481f8ed024d8ba34c9b903321b04864db333e558ae28653dffb2",
+               "3b8f91443480e647473a0a0b03d571c622b7e70e4309a02c9bb7980053010d865e6aec161354dc9f481b2cd5213e09432b57ec4e58fbd0a8549dd15c8c4e74a6529f75fad0ce5a9e20e2beeb2f91eb638bf88999968de438d2f1cedbfb0a1c81f9e8e7362c738e0fddd963692a4f4df9276b7f040979ce874cf6fa3de26da0713784bdb25e4efcb840554ef5b38b5fe8380549a496bd8e423a7456df6f4ae78a07ebe2276a8e22fc2243ec4f78abe0c99c733fd67c8c492699fa5ee2289cdd0a8d469bf883520ee74efb854bfadc7366a49ee65ca4e894e3335e2b672618d362eee12a577dd8dc2ba55c49c1fc3ad68180e9b112d0234d4aa28f5661f1e036450ca6f18be0166676bd80f8a4890c6ddea306fabb7ff3cb2860aa32a827e3a312912a2dfa70f6bc1c07de238448f2d751bd0cf15bf7",
+       },
+       {
+               "e2e001a36c60d2bf40d69ff5b2b1161ea218db263be16a4e",
+               "84230643130d05425826641e",
+               "adb034f3f4a7ca45e2993812d113a9821d50df151af978bccc6d3bc113e15bc0918fb385377dca1916022ce816d56a332649484043c0fc0f2d37d040182b00a9bbb42ef231f80b48fb3730110d9a4433e38c73264c703579a705b9c031b969ec6d98de9f90e9e78b21179c2eb1e061946cd4bbb844f031ecf6eaac27a4151311adf1b03eda97c9fbae66295f468af4b35faf6ba39f9d8f95873bbc2b51cf3dfec0ed3c9b850696336cc093b24a8765a936d14dd56edc6bf518272169f75e67b74ba452d0aae90416a997c8f31e2e9d54ffea296dc69462debc8347b3e1af6a2d53bdfdfda601134f98db42b609df0a08c9347590c8d86e845bb6373d65a26ab85f67b50569c85401a396b8ad76c2b53ff62bcfbf033e435ef47b9b591d05117c6dc681d68e",
+               "d5d7316b8fdee152942148bff007c22e4b2022c6bc7be3c18c5f2e52e004e0b5dc12206bf002bd",
+               "f2c39423ee630dfe961da81909159dba018ce09b1073a12a477108316af5b7a31f86be6a0548b572d604bd115ea737dde899e0bd7f7ac9b23e38910dc457551ecc15c814a9f46d8432a1a36097dc1afe2712d1ba0838fa88cb55d9f65a2e9bece0dbf8999562503989041a2c87d7eb80ef649769d2f4978ce5cf9664f2bd0849646aa81cb976e45e1ade2f17a8126219e917aadbb4bae5e2c4b3f57bbc7f13fcc807df7842d9727a1b389e0b749e5191482adacabd812627c6eae2c7a30caf0844ad2a22e08f39edddf0ae10413e47db433dfe3febbb5a5cec9ade21fbba1e548247579395880b747669a8eb7e2ec0c1bff7fed2defdb92b07a14edf07b1bde29c31ab052ff1214e6b5ebbefcb8f21b5d6f8f6e07ee57ad6e14d4e142cb3f51bb465ab3a28a2a12f01b7514ad0463f2bde0d71d221",
+       },
+       {
+               "5394e890d37ba55ec9d5f327f15680f6a63ef5279c79331643ad0af6d2623525",
+               "815e840b7aca7af3b324583f",
+               "8e63067cd15359f796b43c68f093f55fdf3589fc5f2fdfad5f9d156668a617f7091d73da71cdd207810e6f71a165d0809a597df9885ca6e8f9bb4e616166586b83cc45f49917fc1a256b8bc7d05c476ab5c4633e20092619c4747b26dad3915e9fd65238ee4e5213badeda8a3a22f5efe6582d0762532026c89b4ca26fdd000eb45347a2a199b55b7790e6b1b2dba19833ce9f9522c0bcea5b088ccae68dd99ae0203c81b9f1dd3181c3e2339e83ccd1526b67742b235e872bea5111772aab574ae7d904d9b6355a79178e179b5ae8edc54f61f172bf789ea9c9af21f45b783e4251421b077776808f04972a5e801723cf781442378ce0e0568f014aea7a882dcbcb48d342be53d1c2ebfb206b12443a8a587cc1e55ca23beca385d61d0d03e9d84cbc1b0a",
+               "0feccdfae8ed65fa31a0858a1c466f79e8aa658c2f3ba93c3f92158b4e30955e1c62580450beff",
+               "b69a7e17bb5af688883274550a4ded0d1aff49a0b18343f4b382f745c163f7f714c9206a32a1ff012427e19431951edd0a755e5f491b0eedfd7df68bbc6085dd2888607a2f998c3e881eb1694109250db28291e71f4ad344a125624fb92e16ea9815047cd1111cabfdc9cb8c3b4b0f40aa91d31774009781231400789ed545404af6c3f76d07ddc984a7bd8f52728159782832e298cc4d529be96d17be898efd83e44dc7b0e2efc645849fd2bba61fef0ae7be0dcab233cc4e2b7ba4e887de9c64b97f2a1818aa54371a8d629dae37975f7784e5e3cc77055ed6e975b1e5f55e6bbacdc9f295ce4ada2c16113cd5b323cf78b7dde39f4a87aa8c141a31174e3584ccbd380cf5ec6d1dba539928b084fa9683e9c0953acf47cc3ac384a2c38914f1da01fb2cfd78905c2b58d36b2574b9df15535d82",
+       },
 }
 
 func TestAESGCM(t *testing.T) {
@@ -186,3 +240,37 @@ func TestAESGCM(t *testing.T) {
                ct[0] ^= 0x80
        }
 }
+
+func TestTagFailureOverwrite(t *testing.T) {
+       // The AESNI GCM code decrypts and authenticates concurrently and so
+       // overwrites the output buffer before checking the authentication tag.
+       // In order to be consistent across platforms, all implementations
+       // should do this and this test checks that.
+
+       key, _ := hex.DecodeString("ab72c77b97cb5fe9a382d9fe81ffdbed")
+       nonce, _ := hex.DecodeString("54cc7dc2c37ec006bcc6d1db")
+       ciphertext, _ := hex.DecodeString("0e1bde206a07a9c2c1b65300f8c649972b4401346697138c7a4891ee59867d0c")
+
+       aes, _ := aes.NewCipher(key)
+       aesgcm, _ := cipher.NewGCM(aes)
+
+       dst := make([]byte, len(ciphertext)-16)
+       for i := range dst {
+               dst[i] = 42
+       }
+
+       result, err := aesgcm.Open(dst[:0], nonce, ciphertext, nil)
+       if err == nil {
+               t.Fatal("Bad Open still resulted in nil error.")
+       }
+
+       if result != nil {
+               t.Fatal("Failed Open returned non-nil result.")
+       }
+
+       for i := range dst {
+               if dst[i] != 0 {
+                       t.Fatal("Failed Open didn't zero dst buffer")
+               }
+       }
+}
index 184ea9d4d62c74ae04419ca5cf8edb1f7f883d17..a80ebd36931eac75c9a841bd207edbf2b379df46 100644 (file)
@@ -109,7 +109,7 @@ type Signer interface {
        // private key.
        Public() PublicKey
 
-       // Sign signs msg with the private key, possibly using entropy from
+       // Sign signs digest with the private key, possibly using entropy from
        // rand. For an RSA key, the resulting signature should be either a
        // PKCS#1 v1.5 or PSS signature (as indicated by opts). For an (EC)DSA
        // key, it should be a DER-serialised, ASN.1 signature structure.
@@ -118,7 +118,11 @@ type Signer interface {
        // simply pass in the hash function used as opts. Sign may also attempt
        // to type assert opts to other types in order to obtain algorithm
        // specific values. See the documentation in each package for details.
-       Sign(rand io.Reader, msg []byte, opts SignerOpts) (signature []byte, err error)
+       //
+       // Note that when a signature of a hash of a larger message is needed,
+       // the caller is responsible for hashing the larger message and passing
+       // the hash (as digest) and the hash function (as opts) to Sign.
+       Sign(rand io.Reader, digest []byte, opts SignerOpts) (signature []byte, err error)
 }
 
 // SignerOpts contains options for signing with a Signer.
index b7565a61b0293899a9fd8e722f6d66fafb3471eb..28e981b9dde5a3dfdad1194375c8f866e8e43a8f 100644 (file)
@@ -51,7 +51,7 @@ const (
 const numMRTests = 64
 
 // GenerateParameters puts a random, valid set of DSA parameters into params.
-// This function takes many seconds, even on fast machines.
+// This function can take many seconds, even on fast machines.
 func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) (err error) {
        // This function doesn't follow FIPS 186-3 exactly in that it doesn't
        // use a verification seed to generate the primes. The verification
index 8d66477fd10d2871e0b4bc571383a683058db4fe..0731f2b670345dc0336f231cafaf454647dc46dc 100644 (file)
@@ -27,6 +27,17 @@ import (
        "math/big"
 )
 
+// A invertible implements fast inverse mod Curve.Params().N
+type invertible interface {
+       // Inverse returns the inverse of k in GF(P)
+       Inverse(k *big.Int) *big.Int
+}
+
+// combinedMult implements fast multiplication S1*g + S2*p (g - generator, p - arbitrary point)
+type combinedMult interface {
+       CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int)
+}
+
 const (
        aesIV = "IV for ECDSA CTR"
 )
@@ -179,7 +190,12 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
                                return
                        }
 
-                       kInv = fermatInverse(k, N)
+                       if in, ok := priv.Curve.(invertible); ok {
+                               kInv = in.Inverse(k)
+                       } else {
+                               kInv = fermatInverse(k, N)
+                       }
+
                        r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
                        r.Mod(r, N)
                        if r.Sign() != 0 {
@@ -214,16 +230,29 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
                return false
        }
        e := hashToInt(hash, c)
-       w := new(big.Int).ModInverse(s, N)
+
+       var w *big.Int
+       if in, ok := c.(invertible); ok {
+               w = in.Inverse(s)
+       } else {
+               w = new(big.Int).ModInverse(s, N)
+       }
 
        u1 := e.Mul(e, w)
        u1.Mod(u1, N)
        u2 := w.Mul(r, w)
        u2.Mod(u2, N)
 
-       x1, y1 := c.ScalarBaseMult(u1.Bytes())
-       x2, y2 := c.ScalarMult(pub.X, pub.Y, u2.Bytes())
-       x, y := c.Add(x1, y1, x2, y2)
+       // Check if implements S1*g + S2*p
+       var x, y *big.Int
+       if opt, ok := c.(combinedMult); ok {
+               x, y = opt.CombinedMult(pub.X, pub.Y, u1.Bytes(), u2.Bytes())
+       } else {
+               x1, y1 := c.ScalarBaseMult(u1.Bytes())
+               x2, y2 := c.ScalarMult(pub.X, pub.Y, u2.Bytes())
+               x, y = c.Add(x1, y1, x2, y2)
+       }
+
        if x.Sign() == 0 && y.Sign() == 0 {
                return false
        }
index 169944dfb27b2207cd1076aed95dc2a037a21328..62a3fcc49641349a5f99ee4b30cf137d652aa0c4 100644 (file)
@@ -42,6 +42,41 @@ func TestKeyGeneration(t *testing.T) {
        testKeyGeneration(t, elliptic.P521(), "p521")
 }
 
+func BenchmarkSignP256(b *testing.B) {
+       b.ResetTimer()
+       p256 := elliptic.P256()
+       hashed := []byte("testing")
+       priv, _ := GenerateKey(p256, rand.Reader)
+
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               _, _, _ = Sign(rand.Reader, priv, hashed)
+       }
+}
+
+func BenchmarkVerifyP256(b *testing.B) {
+       b.ResetTimer()
+       p256 := elliptic.P256()
+       hashed := []byte("testing")
+       priv, _ := GenerateKey(p256, rand.Reader)
+       r, s, _ := Sign(rand.Reader, priv, hashed)
+
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               Verify(&priv.PublicKey, hashed, r, s)
+       }
+}
+
+func BenchmarkKeyGeneration(b *testing.B) {
+       b.ResetTimer()
+       p256 := elliptic.P256()
+
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               GenerateKey(p256, rand.Reader)
+       }
+}
+
 func testSignAndVerify(t *testing.T, c elliptic.Curve, tag string) {
        priv, _ := GenerateKey(c, rand.Reader)
 
@@ -91,11 +126,11 @@ func testNonceSafety(t *testing.T, c elliptic.Curve, tag string) {
 
        if s0.Cmp(s1) == 0 {
                // This should never happen.
-               t.Errorf("%s: the signatures on two different messages were the same")
+               t.Errorf("%s: the signatures on two different messages were the same", tag)
        }
 
        if r0.Cmp(r1) == 0 {
-               t.Errorf("%s: the nonce used for two diferent messages was the same")
+               t.Errorf("%s: the nonce used for two diferent messages was the same", tag)
        }
 }
 
@@ -126,11 +161,11 @@ func testINDCCA(t *testing.T, c elliptic.Curve, tag string) {
        }
 
        if s0.Cmp(s1) == 0 {
-               t.Errorf("%s: two signatures of the same message produced the same result")
+               t.Errorf("%s: two signatures of the same message produced the same result", tag)
        }
 
        if r0.Cmp(r1) == 0 {
-               t.Errorf("%s: two signatures of the same message produced the same nonce")
+               t.Errorf("%s: two signatures of the same message produced the same nonce", tag)
        }
 }
 
index e6b59c5f436b9d24a8a61e093bd2adcc079e72ba..c02df45d10502d129bf3bf48406593492d8d85c9 100644 (file)
@@ -274,7 +274,8 @@ var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f}
 // GenerateKey returns a public/private key pair. The private key is
 // generated using the given reader, which must return random data.
 func GenerateKey(curve Curve, rand io.Reader) (priv []byte, x, y *big.Int, err error) {
-       bitSize := curve.Params().BitSize
+       N := curve.Params().N
+       bitSize := N.BitLen()
        byteLen := (bitSize + 7) >> 3
        priv = make([]byte, byteLen)
 
@@ -289,6 +290,12 @@ func GenerateKey(curve Curve, rand io.Reader) (priv []byte, x, y *big.Int, err e
                // This is because, in tests, rand will return all zeros and we don't
                // want to get the point at infinity and loop forever.
                priv[1] ^= 0x42
+
+               // If the scalar is out of range, sample another random number.
+               if new(big.Int).SetBytes(priv).Cmp(N) >= 0 {
+                       continue
+               }
+
                x, y = curve.ScalarBaseMult(priv)
        }
        return
index 7e27913dcd0505001411377f2f4fab3ebfb21d65..7f3f1a21187403caf0f1e0362b006f1d5a82eb6f 100644 (file)
@@ -441,6 +441,18 @@ func BenchmarkBaseMultP256(b *testing.B) {
        }
 }
 
+func BenchmarkScalarMultP256(b *testing.B) {
+       b.ResetTimer()
+       p256 := P256()
+       _, x, y, _ := GenerateKey(p256, rand.Reader)
+       priv, _, _, _ := GenerateKey(p256, rand.Reader)
+
+       b.StartTimer()
+       for i := 0; i < b.N; i++ {
+               p256.ScalarMult(x, y, priv)
+       }
+}
+
 func TestMarshal(t *testing.T) {
        p224 := P224()
        _, x, y, err := GenerateKey(p224, rand.Reader)
index 82bc7b3019e62c6d7fd468bb2b59b88c43c3201e..5103e86de9e408ef2d0cf4dbec5d59967520ad7c 100644 (file)
@@ -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
+
 package elliptic
 
 // This file contains a constant-time, 32-bit implementation of P256.
diff --git a/libgo/go/crypto/elliptic/p256_amd64.go b/libgo/go/crypto/elliptic/p256_amd64.go
new file mode 100644 (file)
index 0000000..586cd10
--- /dev/null
@@ -0,0 +1,552 @@
+// Copyright 2015 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.
+
+// This file contains the Go wrapper for the constant-time, 64-bit assembly
+// implementation of P256. The optimizations performed here are described in
+// detail in:
+// S.Gueron and V.Krasnov, "Fast prime field elliptic-curve cryptography with
+//                          256-bit primes"
+// http://link.springer.com/article/10.1007%2Fs13389-014-0090-x
+// https://eprint.iacr.org/2013/816.pdf
+
+// +build amd64
+
+package elliptic
+
+import (
+       "math/big"
+       "sync"
+)
+
+type (
+       p256Curve struct {
+               *CurveParams
+       }
+
+       p256Point struct {
+               xyz [12]uint64
+       }
+)
+
+var (
+       p256            p256Curve
+       p256Precomputed *[37][64 * 8]uint64
+       precomputeOnce  sync.Once
+)
+
+func initP256() {
+       // See FIPS 186-3, section D.2.3
+       p256.CurveParams = &CurveParams{Name: "P-256"}
+       p256.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)
+       p256.N, _ = new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10)
+       p256.B, _ = new(big.Int).SetString("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)
+       p256.Gx, _ = new(big.Int).SetString("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16)
+       p256.Gy, _ = new(big.Int).SetString("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16)
+       p256.BitSize = 256
+}
+
+func (curve p256Curve) Params() *CurveParams {
+       return curve.CurveParams
+}
+
+// Functions implemented in p256_asm_amd64.s
+// Montgomery multiplication modulo P256
+func p256Mul(res, in1, in2 []uint64)
+
+// Montgomery square modulo P256
+func p256Sqr(res, in []uint64)
+
+// Montgomery multiplication by 1
+func p256FromMont(res, in []uint64)
+
+// iff cond == 1  val <- -val
+func p256NegCond(val []uint64, cond int)
+
+// if cond == 0 res <- b; else res <- a
+func p256MovCond(res, a, b []uint64, cond int)
+
+// Endianess swap
+func p256BigToLittle(res []uint64, in []byte)
+func p256LittleToBig(res []byte, in []uint64)
+
+// Constant time table access
+func p256Select(point, table []uint64, idx int)
+func p256SelectBase(point, table []uint64, idx int)
+
+// Montgomery multiplication modulo Ord(G)
+func p256OrdMul(res, in1, in2 []uint64)
+
+// Montgomery square modulo Ord(G), repeated n times
+func p256OrdSqr(res, in []uint64, n int)
+
+// Point add with in2 being affine point
+// If sign == 1 -> in2 = -in2
+// If sel == 0 -> res = in1
+// if zero == 0 -> res = in2
+func p256PointAddAffineAsm(res, in1, in2 []uint64, sign, sel, zero int)
+
+// Point add
+func p256PointAddAsm(res, in1, in2 []uint64)
+
+// Point double
+func p256PointDoubleAsm(res, in []uint64)
+
+func (curve p256Curve) Inverse(k *big.Int) *big.Int {
+       if k.Cmp(p256.N) >= 0 {
+               // This should never happen.
+               reducedK := new(big.Int).Mod(k, p256.N)
+               k = reducedK
+       }
+
+       // table will store precomputed powers of x. The four words at index
+       // 4×i store x^(i+1).
+       var table [4 * 15]uint64
+
+       x := make([]uint64, 4)
+       fromBig(x[:], k)
+       // This code operates in the Montgomery domain where R = 2^256 mod n
+       // and n is the order of the scalar field. (See initP256 for the
+       // value.) Elements in the Montgomery domain take the form a×R and
+       // multiplication of x and y in the calculates (x × y × R^-1) mod n. RR
+       // is R×R mod n thus the Montgomery multiplication x and RR gives x×R,
+       // i.e. converts x into the Montgomery domain.
+       RR := []uint64{0x83244c95be79eea2, 0x4699799c49bd6fa6, 0x2845b2392b6bec59, 0x66e12d94f3d95620}
+       p256OrdMul(table[:4], x, RR)
+
+       // Prepare the table, no need in constant time access, because the
+       // power is not a secret. (Entry 0 is never used.)
+       for i := 2; i < 16; i += 2 {
+               p256OrdSqr(table[4*(i-1):], table[4*((i/2)-1):], 1)
+               p256OrdMul(table[4*i:], table[4*(i-1):], table[:4])
+       }
+
+       x[0] = table[4*14+0] // f
+       x[1] = table[4*14+1]
+       x[2] = table[4*14+2]
+       x[3] = table[4*14+3]
+
+       p256OrdSqr(x, x, 4)
+       p256OrdMul(x, x, table[4*14:4*14+4]) // ff
+       t := make([]uint64, 4, 4)
+       t[0] = x[0]
+       t[1] = x[1]
+       t[2] = x[2]
+       t[3] = x[3]
+
+       p256OrdSqr(x, x, 8)
+       p256OrdMul(x, x, t) // ffff
+       t[0] = x[0]
+       t[1] = x[1]
+       t[2] = x[2]
+       t[3] = x[3]
+
+       p256OrdSqr(x, x, 16)
+       p256OrdMul(x, x, t) // ffffffff
+       t[0] = x[0]
+       t[1] = x[1]
+       t[2] = x[2]
+       t[3] = x[3]
+
+       p256OrdSqr(x, x, 64) // ffffffff0000000000000000
+       p256OrdMul(x, x, t)  // ffffffff00000000ffffffff
+       p256OrdSqr(x, x, 32) // ffffffff00000000ffffffff00000000
+       p256OrdMul(x, x, t)  // ffffffff00000000ffffffffffffffff
+
+       // Remaining 32 windows
+       expLo := [32]byte{0xb, 0xc, 0xe, 0x6, 0xf, 0xa, 0xa, 0xd, 0xa, 0x7, 0x1, 0x7, 0x9, 0xe, 0x8, 0x4, 0xf, 0x3, 0xb, 0x9, 0xc, 0xa, 0xc, 0x2, 0xf, 0xc, 0x6, 0x3, 0x2, 0x5, 0x4, 0xf}
+       for i := 0; i < 32; i++ {
+               p256OrdSqr(x, x, 4)
+               p256OrdMul(x, x, table[4*(expLo[i]-1):])
+       }
+
+       // Multiplying by one in the Montgomery domain converts a Montgomery
+       // value out of the domain.
+       one := []uint64{1, 0, 0, 0}
+       p256OrdMul(x, x, one)
+
+       xOut := make([]byte, 32)
+       p256LittleToBig(xOut, x)
+       return new(big.Int).SetBytes(xOut)
+}
+
+// fromBig converts a *big.Int into a format used by this code.
+func fromBig(out []uint64, big *big.Int) {
+       for i := range out {
+               out[i] = 0
+       }
+
+       for i, v := range big.Bits() {
+               out[i] = uint64(v)
+       }
+}
+
+// p256GetScalar endian-swaps the big-endian scalar value from in and writes it
+// to out. If the scalar is equal or greater than the order of the group, it's
+// reduced modulo that order.
+func p256GetScalar(out []uint64, in []byte) {
+       n := new(big.Int).SetBytes(in)
+
+       if n.Cmp(p256.N) >= 0 {
+               n.Mod(n, p256.N)
+       }
+       fromBig(out, n)
+}
+
+// p256Mul operates in a Montgomery domain with R = 2^256 mod p, where p is the
+// underlying field of the curve. (See initP256 for the value.) Thus rr here is
+// R×R mod p. See comment in Inverse about how this is used.
+var rr = []uint64{0x0000000000000003, 0xfffffffbffffffff, 0xfffffffffffffffe, 0x00000004fffffffd}
+
+func maybeReduceModP(in *big.Int) *big.Int {
+       if in.Cmp(p256.P) < 0 {
+               return in
+       }
+       return new(big.Int).Mod(in, p256.P)
+}
+
+func (curve p256Curve) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) {
+       scalarReversed := make([]uint64, 4)
+       var r1, r2 p256Point
+       p256GetScalar(scalarReversed, baseScalar)
+       r1.p256BaseMult(scalarReversed)
+
+       p256GetScalar(scalarReversed, scalar)
+       fromBig(r2.xyz[0:4], maybeReduceModP(bigX))
+       fromBig(r2.xyz[4:8], maybeReduceModP(bigY))
+       p256Mul(r2.xyz[0:4], r2.xyz[0:4], rr[:])
+       p256Mul(r2.xyz[4:8], r2.xyz[4:8], rr[:])
+
+       // This sets r2's Z value to 1, in the Montgomery domain.
+       r2.xyz[8] = 0x0000000000000001
+       r2.xyz[9] = 0xffffffff00000000
+       r2.xyz[10] = 0xffffffffffffffff
+       r2.xyz[11] = 0x00000000fffffffe
+
+       r2.p256ScalarMult(scalarReversed)
+       p256PointAddAsm(r1.xyz[:], r1.xyz[:], r2.xyz[:])
+       return r1.p256PointToAffine()
+}
+
+func (curve p256Curve) ScalarBaseMult(scalar []byte) (x, y *big.Int) {
+       scalarReversed := make([]uint64, 4)
+       p256GetScalar(scalarReversed, scalar)
+
+       var r p256Point
+       r.p256BaseMult(scalarReversed)
+       return r.p256PointToAffine()
+}
+
+func (curve p256Curve) ScalarMult(bigX, bigY *big.Int, scalar []byte) (x, y *big.Int) {
+       scalarReversed := make([]uint64, 4)
+       p256GetScalar(scalarReversed, scalar)
+
+       var r p256Point
+       fromBig(r.xyz[0:4], maybeReduceModP(bigX))
+       fromBig(r.xyz[4:8], maybeReduceModP(bigY))
+       p256Mul(r.xyz[0:4], r.xyz[0:4], rr[:])
+       p256Mul(r.xyz[4:8], r.xyz[4:8], rr[:])
+       // This sets r2's Z value to 1, in the Montgomery domain.
+       r.xyz[8] = 0x0000000000000001
+       r.xyz[9] = 0xffffffff00000000
+       r.xyz[10] = 0xffffffffffffffff
+       r.xyz[11] = 0x00000000fffffffe
+
+       r.p256ScalarMult(scalarReversed)
+       return r.p256PointToAffine()
+}
+
+func (p *p256Point) p256PointToAffine() (x, y *big.Int) {
+       zInv := make([]uint64, 4)
+       zInvSq := make([]uint64, 4)
+       p256Inverse(zInv, p.xyz[8:12])
+       p256Sqr(zInvSq, zInv)
+       p256Mul(zInv, zInv, zInvSq)
+
+       p256Mul(zInvSq, p.xyz[0:4], zInvSq)
+       p256Mul(zInv, p.xyz[4:8], zInv)
+
+       p256FromMont(zInvSq, zInvSq)
+       p256FromMont(zInv, zInv)
+
+       xOut := make([]byte, 32)
+       yOut := make([]byte, 32)
+       p256LittleToBig(xOut, zInvSq)
+       p256LittleToBig(yOut, zInv)
+
+       return new(big.Int).SetBytes(xOut), new(big.Int).SetBytes(yOut)
+}
+
+// p256Inverse sets out to in^-1 mod p.
+func p256Inverse(out, in []uint64) {
+       var stack [6 * 4]uint64
+       p2 := stack[4*0 : 4*0+4]
+       p4 := stack[4*1 : 4*1+4]
+       p8 := stack[4*2 : 4*2+4]
+       p16 := stack[4*3 : 4*3+4]
+       p32 := stack[4*4 : 4*4+4]
+
+       p256Sqr(out, in)
+       p256Mul(p2, out, in) // 3*p
+
+       p256Sqr(out, p2)
+       p256Sqr(out, out)
+       p256Mul(p4, out, p2) // f*p
+
+       p256Sqr(out, p4)
+       p256Sqr(out, out)
+       p256Sqr(out, out)
+       p256Sqr(out, out)
+       p256Mul(p8, out, p4) // ff*p
+
+       p256Sqr(out, p8)
+
+       for i := 0; i < 7; i++ {
+               p256Sqr(out, out)
+       }
+       p256Mul(p16, out, p8) // ffff*p
+
+       p256Sqr(out, p16)
+       for i := 0; i < 15; i++ {
+               p256Sqr(out, out)
+       }
+       p256Mul(p32, out, p16) // ffffffff*p
+
+       p256Sqr(out, p32)
+
+       for i := 0; i < 31; i++ {
+               p256Sqr(out, out)
+       }
+       p256Mul(out, out, in)
+
+       for i := 0; i < 32*4; i++ {
+               p256Sqr(out, out)
+       }
+       p256Mul(out, out, p32)
+
+       for i := 0; i < 32; i++ {
+               p256Sqr(out, out)
+       }
+       p256Mul(out, out, p32)
+
+       for i := 0; i < 16; i++ {
+               p256Sqr(out, out)
+       }
+       p256Mul(out, out, p16)
+
+       for i := 0; i < 8; i++ {
+               p256Sqr(out, out)
+       }
+       p256Mul(out, out, p8)
+
+       p256Sqr(out, out)
+       p256Sqr(out, out)
+       p256Sqr(out, out)
+       p256Sqr(out, out)
+       p256Mul(out, out, p4)
+
+       p256Sqr(out, out)
+       p256Sqr(out, out)
+       p256Mul(out, out, p2)
+
+       p256Sqr(out, out)
+       p256Sqr(out, out)
+       p256Mul(out, out, in)
+}
+
+func (p *p256Point) p256StorePoint(r *[16 * 4 * 3]uint64, index int) {
+       copy(r[index*12:], p.xyz[:])
+}
+
+func boothW5(in uint) (int, int) {
+       var s uint = ^((in >> 5) - 1)
+       var d uint = (1 << 6) - in - 1
+       d = (d & s) | (in & (^s))
+       d = (d >> 1) + (d & 1)
+       return int(d), int(s & 1)
+}
+
+func boothW7(in uint) (int, int) {
+       var s uint = ^((in >> 7) - 1)
+       var d uint = (1 << 8) - in - 1
+       d = (d & s) | (in & (^s))
+       d = (d >> 1) + (d & 1)
+       return int(d), int(s & 1)
+}
+
+func initTable() {
+       p256Precomputed = new([37][64 * 8]uint64)
+
+       basePoint := []uint64{
+               0x79e730d418a9143c, 0x75ba95fc5fedb601, 0x79fb732b77622510, 0x18905f76a53755c6,
+               0xddf25357ce95560a, 0x8b4ab8e4ba19e45c, 0xd2e88688dd21f325, 0x8571ff1825885d85,
+               0x0000000000000001, 0xffffffff00000000, 0xffffffffffffffff, 0x00000000fffffffe,
+       }
+       t1 := make([]uint64, 12)
+       t2 := make([]uint64, 12)
+       copy(t2, basePoint)
+
+       zInv := make([]uint64, 4)
+       zInvSq := make([]uint64, 4)
+       for j := 0; j < 64; j++ {
+               copy(t1, t2)
+               for i := 0; i < 37; i++ {
+                       // The window size is 7 so we need to double 7 times.
+                       if i != 0 {
+                               for k := 0; k < 7; k++ {
+                                       p256PointDoubleAsm(t1, t1)
+                               }
+                       }
+                       // Convert the point to affine form. (Its values are
+                       // still in Montgomery form however.)
+                       p256Inverse(zInv, t1[8:12])
+                       p256Sqr(zInvSq, zInv)
+                       p256Mul(zInv, zInv, zInvSq)
+
+                       p256Mul(t1[:4], t1[:4], zInvSq)
+                       p256Mul(t1[4:8], t1[4:8], zInv)
+
+                       copy(t1[8:12], basePoint[8:12])
+                       // Update the table entry
+                       copy(p256Precomputed[i][j*8:], t1[:8])
+               }
+               if j == 0 {
+                       p256PointDoubleAsm(t2, basePoint)
+               } else {
+                       p256PointAddAsm(t2, t2, basePoint)
+               }
+       }
+}
+
+func (p *p256Point) p256BaseMult(scalar []uint64) {
+       precomputeOnce.Do(initTable)
+
+       wvalue := (scalar[0] << 1) & 0xff
+       sel, sign := boothW7(uint(wvalue))
+       p256SelectBase(p.xyz[0:8], p256Precomputed[0][0:], sel)
+       p256NegCond(p.xyz[4:8], sign)
+
+       // (This is one, in the Montgomery domain.)
+       p.xyz[8] = 0x0000000000000001
+       p.xyz[9] = 0xffffffff00000000
+       p.xyz[10] = 0xffffffffffffffff
+       p.xyz[11] = 0x00000000fffffffe
+
+       var t0 p256Point
+       // (This is one, in the Montgomery domain.)
+       t0.xyz[8] = 0x0000000000000001
+       t0.xyz[9] = 0xffffffff00000000
+       t0.xyz[10] = 0xffffffffffffffff
+       t0.xyz[11] = 0x00000000fffffffe
+
+       index := uint(6)
+       zero := sel
+
+       for i := 1; i < 37; i++ {
+               if index < 192 {
+                       wvalue = ((scalar[index/64] >> (index % 64)) + (scalar[index/64+1] << (64 - (index % 64)))) & 0xff
+               } else {
+                       wvalue = (scalar[index/64] >> (index % 64)) & 0xff
+               }
+               index += 7
+               sel, sign = boothW7(uint(wvalue))
+               p256SelectBase(t0.xyz[0:8], p256Precomputed[i][0:], sel)
+               p256PointAddAffineAsm(p.xyz[0:12], p.xyz[0:12], t0.xyz[0:8], sign, sel, zero)
+               zero |= sel
+       }
+}
+
+func (p *p256Point) p256ScalarMult(scalar []uint64) {
+       // precomp is a table of precomputed points that stores powers of p
+       // from p^1 to p^16.
+       var precomp [16 * 4 * 3]uint64
+       var t0, t1, t2, t3 p256Point
+
+       // Prepare the table
+       p.p256StorePoint(&precomp, 0) // 1
+
+       p256PointDoubleAsm(t0.xyz[:], p.xyz[:])
+       p256PointDoubleAsm(t1.xyz[:], t0.xyz[:])
+       p256PointDoubleAsm(t2.xyz[:], t1.xyz[:])
+       p256PointDoubleAsm(t3.xyz[:], t2.xyz[:])
+       t0.p256StorePoint(&precomp, 1)  // 2
+       t1.p256StorePoint(&precomp, 3)  // 4
+       t2.p256StorePoint(&precomp, 7)  // 8
+       t3.p256StorePoint(&precomp, 15) // 16
+
+       p256PointAddAsm(t0.xyz[:], t0.xyz[:], p.xyz[:])
+       p256PointAddAsm(t1.xyz[:], t1.xyz[:], p.xyz[:])
+       p256PointAddAsm(t2.xyz[:], t2.xyz[:], p.xyz[:])
+       t0.p256StorePoint(&precomp, 2) // 3
+       t1.p256StorePoint(&precomp, 4) // 5
+       t2.p256StorePoint(&precomp, 8) // 9
+
+       p256PointDoubleAsm(t0.xyz[:], t0.xyz[:])
+       p256PointDoubleAsm(t1.xyz[:], t1.xyz[:])
+       t0.p256StorePoint(&precomp, 5) // 6
+       t1.p256StorePoint(&precomp, 9) // 10
+
+       p256PointAddAsm(t2.xyz[:], t0.xyz[:], p.xyz[:])
+       p256PointAddAsm(t1.xyz[:], t1.xyz[:], p.xyz[:])
+       t2.p256StorePoint(&precomp, 6)  // 7
+       t1.p256StorePoint(&precomp, 10) // 11
+
+       p256PointDoubleAsm(t0.xyz[:], t0.xyz[:])
+       p256PointDoubleAsm(t2.xyz[:], t2.xyz[:])
+       t0.p256StorePoint(&precomp, 11) // 12
+       t2.p256StorePoint(&precomp, 13) // 14
+
+       p256PointAddAsm(t0.xyz[:], t0.xyz[:], p.xyz[:])
+       p256PointAddAsm(t2.xyz[:], t2.xyz[:], p.xyz[:])
+       t0.p256StorePoint(&precomp, 12) // 13
+       t2.p256StorePoint(&precomp, 14) // 15
+
+       // Start scanning the window from top bit
+       index := uint(254)
+       var sel, sign int
+
+       wvalue := (scalar[index/64] >> (index % 64)) & 0x3f
+       sel, _ = boothW5(uint(wvalue))
+
+       p256Select(p.xyz[0:12], precomp[0:], sel)
+       zero := sel
+
+       for index > 4 {
+               index -= 5
+               p256PointDoubleAsm(p.xyz[:], p.xyz[:])
+               p256PointDoubleAsm(p.xyz[:], p.xyz[:])
+               p256PointDoubleAsm(p.xyz[:], p.xyz[:])
+               p256PointDoubleAsm(p.xyz[:], p.xyz[:])
+               p256PointDoubleAsm(p.xyz[:], p.xyz[:])
+
+               if index < 192 {
+                       wvalue = ((scalar[index/64] >> (index % 64)) + (scalar[index/64+1] << (64 - (index % 64)))) & 0x3f
+               } else {
+                       wvalue = (scalar[index/64] >> (index % 64)) & 0x3f
+               }
+
+               sel, sign = boothW5(uint(wvalue))
+
+               p256Select(t0.xyz[0:], precomp[0:], sel)
+               p256NegCond(t0.xyz[4:8], sign)
+               p256PointAddAsm(t1.xyz[:], p.xyz[:], t0.xyz[:])
+               p256MovCond(t1.xyz[0:12], t1.xyz[0:12], p.xyz[0:12], sel)
+               p256MovCond(p.xyz[0:12], t1.xyz[0:12], t0.xyz[0:12], zero)
+               zero |= sel
+       }
+
+       p256PointDoubleAsm(p.xyz[:], p.xyz[:])
+       p256PointDoubleAsm(p.xyz[:], p.xyz[:])
+       p256PointDoubleAsm(p.xyz[:], p.xyz[:])
+       p256PointDoubleAsm(p.xyz[:], p.xyz[:])
+       p256PointDoubleAsm(p.xyz[:], p.xyz[:])
+
+       wvalue = (scalar[0] << 1) & 0x3f
+       sel, sign = boothW5(uint(wvalue))
+
+       p256Select(t0.xyz[0:], precomp[0:], sel)
+       p256NegCond(t0.xyz[4:8], sign)
+       p256PointAddAsm(t1.xyz[:], p.xyz[:], t0.xyz[:])
+       p256MovCond(t1.xyz[0:12], t1.xyz[0:12], p.xyz[0:12], sel)
+       p256MovCond(p.xyz[0:12], t1.xyz[0:12], t0.xyz[0:12], zero)
+}
index e0cc1d6d2241331c02f2fd489e4c5efff5fb2c52..3b41cde0bd50f4684a84b7a89de274f53acafca1 100644 (file)
@@ -26,8 +26,8 @@ import (
        "hash"
 )
 
-// FIPS 198:
-// http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
+// FIPS 198-1:
+// http://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf
 
 // key is zero padded to the block size of the hash function
 // ipad = 0x36 byte repeated for key length
index 8c50c6d0bfaa7db920a48988ae5af5ecff7dd411..a3550cb7dda2891e2ae6fa2f22d7e01c7c3726cd 100644 (file)
@@ -62,16 +62,10 @@ func (d *digest) Write(p []byte) (nn int, err error) {
        nn = len(p)
        d.len += uint64(nn)
        if d.nx > 0 {
-               n := len(p)
-               if n > chunk-d.nx {
-                       n = chunk - d.nx
-               }
-               for i := 0; i < n; i++ {
-                       d.x[d.nx+i] = p[i]
-               }
+               n := copy(d.x[d.nx:], p)
                d.nx += n
                if d.nx == chunk {
-                       block(d, d.x[0:chunk])
+                       block(d, d.x[:])
                        d.nx = 0
                }
                p = p[n:]
diff --git a/libgo/go/crypto/rsa/example_test.go b/libgo/go/crypto/rsa/example_test.go
new file mode 100644 (file)
index 0000000..1435b70
--- /dev/null
@@ -0,0 +1,169 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rsa
+
+import (
+       "crypto"
+       "crypto/aes"
+       "crypto/cipher"
+       "crypto/rand"
+       "crypto/sha256"
+       "encoding/hex"
+       "fmt"
+       "io"
+       "os"
+)
+
+// RSA is able to encrypt only a very limited amount of data. In order
+// to encrypt reasonable amounts of data a hybrid scheme is commonly
+// used: RSA is used to encrypt a key for a symmetric primitive like
+// AES-GCM.
+//
+// Before encrypting, data is “padded” by embedding it in a known
+// structure. This is done for a number of reasons, but the most
+// obvious is to ensure that the value is large enough that the
+// exponentiation is larger than the modulus. (Otherwise it could be
+// decrypted with a square-root.)
+//
+// In these designs, when using PKCS#1 v1.5, it's vitally important to
+// avoid disclosing whether the received RSA message was well-formed
+// (that is, whether the result of decrypting is a correctly padded
+// message) because this leaks secret information.
+// DecryptPKCS1v15SessionKey is designed for this situation and copies
+// the decrypted, symmetric key (if well-formed) in constant-time over
+// a buffer that contains a random key. Thus, if the RSA result isn't
+// well-formed, the implementation uses a random key in constant time.
+func ExampleDecryptPKCS1v15SessionKey() {
+       // crypto/rand.Reader is a good source of entropy for blinding the RSA
+       // operation.
+       rng := rand.Reader
+
+       // The hybrid scheme should use at least a 16-byte symmetric key. Here
+       // we read the random key that will be used if the RSA decryption isn't
+       // well-formed.
+       key := make([]byte, 32)
+       if _, err := io.ReadFull(rng, key); err != nil {
+               panic("RNG failure")
+       }
+
+       rsaCiphertext, _ := hex.DecodeString("aabbccddeeff")
+
+       if err := DecryptPKCS1v15SessionKey(rng, rsaPrivateKey, rsaCiphertext, key); err != nil {
+               // Any errors that result will be “public” – meaning that they
+               // can be determined without any secret information. (For
+               // instance, if the length of key is impossible given the RSA
+               // public key.)
+               fmt.Fprintf(os.Stderr, "Error from RSA decryption: %s\n", err)
+               return
+       }
+
+       // Given the resulting key, a symmetric scheme can be used to decrypt a
+       // larger ciphertext.
+       block, err := aes.NewCipher(key)
+       if err != nil {
+               panic("aes.NewCipher failed: " + err.Error())
+       }
+
+       // Since the key is random, using a fixed nonce is acceptable as the
+       // (key, nonce) pair will still be unique, as required.
+       var zeroNonce [12]byte
+       aead, err := cipher.NewGCM(block)
+       if err != nil {
+               panic("cipher.NewGCM failed: " + err.Error())
+       }
+       ciphertext, _ := hex.DecodeString("00112233445566")
+       plaintext, err := aead.Open(nil, zeroNonce[:], ciphertext, nil)
+       if err != nil {
+               // The RSA ciphertext was badly formed; the decryption will
+               // fail here because the AES-GCM key will be incorrect.
+               fmt.Fprintf(os.Stderr, "Error decrypting: %s\n", err)
+               return
+       }
+
+       fmt.Printf("Plaintext: %s\n", string(plaintext))
+}
+
+func ExampleSignPKCS1v15() {
+       // crypto/rand.Reader is a good source of entropy for blinding the RSA
+       // operation.
+       rng := rand.Reader
+
+       message := []byte("message to be signed")
+
+       // Only small messages can be signed directly; thus the hash of a
+       // message, rather than the message itself, is signed. This requires
+       // that the hash function be collision resistant. SHA-256 is the
+       // least-strong hash function that should be used for this at the time
+       // of writing (2016).
+       hashed := sha256.Sum256(message)
+
+       signature, err := SignPKCS1v15(rng, rsaPrivateKey, crypto.SHA256, hashed[:])
+       if err != nil {
+               fmt.Fprintf(os.Stderr, "Error from signing: %s\n", err)
+               return
+       }
+
+       fmt.Printf("Signature: %x\n", signature)
+}
+
+func ExampleVerifyPKCS1v15() {
+       message := []byte("message to be signed")
+       signature, _ := hex.DecodeString("ad2766728615cc7a746cc553916380ca7bfa4f8983b990913bc69eb0556539a350ff0f8fe65ddfd3ebe91fe1c299c2fac135bc8c61e26be44ee259f2f80c1530")
+
+       // Only small messages can be signed directly; thus the hash of a
+       // message, rather than the message itself, is signed. This requires
+       // that the hash function be collision resistant. SHA-256 is the
+       // least-strong hash function that should be used for this at the time
+       // of writing (2016).
+       hashed := sha256.Sum256(message)
+
+       err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.SHA256, hashed[:], signature)
+       if err != nil {
+               fmt.Fprintf(os.Stderr, "Error from verification: %s\n", err)
+               return
+       }
+
+       // signature is a valid signature of message from the public key.
+}
+
+func ExampleEncryptOAEP() {
+       secretMessage := []byte("send reinforcements, we're going to advance")
+       label := []byte("orders")
+
+       // crypto/rand.Reader is a good source of entropy for randomizing the
+       // encryption function.
+       rng := rand.Reader
+
+       ciphertext, err := EncryptOAEP(sha256.New(), rng, &test2048Key.PublicKey, secretMessage, label)
+       if err != nil {
+               fmt.Fprintf(os.Stderr, "Error from encryption: %s\n", err)
+               return
+       }
+
+       // Since encryption is a randomized function, ciphertext will be
+       // different each time.
+       fmt.Printf("Ciphertext: %x\n", ciphertext)
+}
+
+func ExampleDecryptOAEP() {
+       ciphertext, _ := hex.DecodeString("4d1ee10e8f286390258c51a5e80802844c3e6358ad6690b7285218a7c7ed7fc3a4c7b950fbd04d4b0239cc060dcc7065ca6f84c1756deb71ca5685cadbb82be025e16449b905c568a19c088a1abfad54bf7ecc67a7df39943ec511091a34c0f2348d04e058fcff4d55644de3cd1d580791d4524b92f3e91695582e6e340a1c50b6c6d78e80b4e42c5b4d45e479b492de42bbd39cc642ebb80226bb5200020d501b24a37bcc2ec7f34e596b4fd6b063de4858dbf5a4e3dd18e262eda0ec2d19dbd8e890d672b63d368768360b20c0b6b8592a438fa275e5fa7f60bef0dd39673fd3989cc54d2cb80c08fcd19dacbc265ee1c6014616b0e04ea0328c2a04e73460")
+       label := []byte("orders")
+
+       // crypto/rand.Reader is a good source of entropy for blinding the RSA
+       // operation.
+       rng := rand.Reader
+
+       plaintext, err := DecryptOAEP(sha256.New(), rng, test2048Key, ciphertext, label)
+       if err != nil {
+               fmt.Fprintf(os.Stderr, "Error from decryption: %s\n", err)
+               return
+       }
+
+       fmt.Printf("Plaintext: %s\n", string(plaintext))
+
+       // Remember that encryption only provides confidentiality. The
+       // ciphertext should be signed before authenticity is assumed and, even
+       // then, consider that messages might be reordered.
+}
index 34037b0d674f72a8d3ec89bba1aa1a3d6c2594e7..5c5f415c88dee0314d5a4ebb2939644f2d743594 100644 (file)
@@ -26,6 +26,10 @@ type PKCS1v15DecryptOptions struct {
 
 // EncryptPKCS1v15 encrypts the given message with RSA and the padding scheme from PKCS#1 v1.5.
 // The message must be no longer than the length of the public modulus minus 11 bytes.
+//
+// The rand parameter is used as a source of entropy to ensure that encrypting
+// the same message twice doesn't result in the same ciphertext.
+//
 // WARNING: use of this function to encrypt plaintexts other than session keys
 // is dangerous. Use RSA OAEP in new protocols.
 func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, err error) {
@@ -59,6 +63,12 @@ func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, er
 
 // DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5.
 // If rand != nil, it uses RSA blinding to avoid timing side-channel attacks.
+//
+// Note that whether this function returns an error or not discloses secret
+// information. If an attacker can cause this function to run repeatedly and
+// learn whether each instance returned an error then they can decrypt and
+// forge signatures as if they had the private key. See
+// DecryptPKCS1v15SessionKey for a way of solving this problem.
 func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out []byte, err error) {
        if err := checkPub(&priv.PublicKey); err != nil {
                return nil, err
@@ -87,6 +97,12 @@ func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out [
 // See ``Chosen Ciphertext Attacks Against Protocols Based on the RSA
 // Encryption Standard PKCS #1'', Daniel Bleichenbacher, Advances in Cryptology
 // (Crypto '98).
+//
+// Note that if the session key is too small then it may be possible for an
+// attacker to brute-force it. If they can do that then they can learn whether
+// a random value was used (because it'll be different for the same ciphertext)
+// and thus whether the padding was correct. This defeats the point of this
+// function. Using at least a 16-byte key will protect against this attack.
 func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) (err error) {
        if err := checkPub(&priv.PublicKey); err != nil {
                return err
@@ -201,6 +217,13 @@ var hashPrefixes = map[crypto.Hash][]byte{
 // Note that hashed must be the result of hashing the input message using the
 // given hash function. If hash is zero, hashed is signed directly. This isn't
 // advisable except for interoperability.
+//
+// If rand is not nil then RSA blinding will be used to avoid timing side-channel attacks.
+//
+// This function is deterministic. Thus, if the set of possible messages is
+// small, an attacker may be able to build a map from messages to signatures
+// and identify the signed messages. As ever, signatures provide authenticity,
+// not confidentiality.
 func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err error) {
        hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
        if err != nil {
@@ -223,7 +246,7 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b
        copy(em[k-hashLen:k], hashed)
 
        m := new(big.Int).SetBytes(em)
-       c, err := decrypt(rand, priv, m)
+       c, err := decryptAndCheck(rand, priv, m)
        if err != nil {
                return
        }
index 89253751ec2696784ed4bf42d654a090a05d360f..47444f311c341b8cc5eaf3430927b85d74d48aaf 100644 (file)
@@ -160,7 +160,7 @@ func TestEncryptPKCS1v15DecrypterSessionKey(t *testing.T) {
                }
 
                if test.out != "FAIL" && !bytes.Equal(plaintext, []byte(test.out)) {
-                       t.Errorf("#%d: incorrect plaintext: got %x, want %x", plaintext, test.out)
+                       t.Errorf("#%d: incorrect plaintext: got %x, want %x", i, plaintext, test.out)
                }
        }
 }
index 0a41814a4b1e7c7a772f5ba3850068cefe88fbe9..8a94589b1c2b7d82222b3c02860442e1e613d706 100644 (file)
@@ -198,7 +198,7 @@ func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed,
                return
        }
        m := new(big.Int).SetBytes(em)
-       c, err := decrypt(rand, priv, m)
+       c, err := decryptAndCheck(rand, priv, m)
        if err != nil {
                return
        }
index 1293b783679b143440aabb2d5a9e04a391273f46..ee022b803ae21fffd6d67ed2922a883c6d56dcbf 100644 (file)
@@ -3,6 +3,21 @@
 // license that can be found in the LICENSE file.
 
 // Package rsa implements RSA encryption as specified in PKCS#1.
+//
+// RSA is a single, fundamental operation that is used in this package to
+// implement either public-key encryption or public-key signatures.
+//
+// The original specification for encryption and signatures with RSA is PKCS#1
+// and the terms "RSA encryption" and "RSA signatures" by default refer to
+// PKCS#1 version 1.5. However, that specification has flaws and new designs
+// should use version two, usually called by just OAEP and PSS, where
+// possible.
+//
+// Two sets of interfaces are included in this package. When a more abstract
+// interface isn't neccessary, there are functions for encrypting/decrypting
+// with v1.5/OAEP and signing/verifying with v1.5/PSS. If one needs to abstract
+// over the public-key primitive, the PrivateKey struct implements the
+// Decrypter and Signer interfaces from the crypto package.
 package rsa
 
 import (
@@ -317,6 +332,20 @@ func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int {
 }
 
 // EncryptOAEP encrypts the given message with RSA-OAEP.
+//
+// OAEP is parameterised by a hash function that is used as a random oracle.
+// Encryption and decryption of a given message must use the same hash function
+// and sha256.New() is a reasonable choice.
+//
+// The random parameter is used as a source of entropy to ensure that
+// encrypting the same message twice doesn't result in the same ciphertext.
+//
+// The label parameter may contain arbitrary data that will not be encrypted,
+// but which gives important context to the message. For example, if a given
+// public key is used to decrypt two types of messages then distinct label
+// values could be used to ensure that a ciphertext for one purpose cannot be
+// used for another by an attacker. If not required it can be empty.
+//
 // The message must be no longer than the length of the public modulus less
 // twice the hash length plus 2.
 func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err error) {
@@ -506,8 +535,33 @@ func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err er
        return
 }
 
+func decryptAndCheck(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err error) {
+       m, err = decrypt(random, priv, c)
+       if err != nil {
+               return nil, err
+       }
+
+       // In order to defend against errors in the CRT computation, m^e is
+       // calculated, which should match the original ciphertext.
+       check := encrypt(new(big.Int), &priv.PublicKey, m)
+       if c.Cmp(check) != 0 {
+               return nil, errors.New("rsa: internal error")
+       }
+       return m, nil
+}
+
 // DecryptOAEP decrypts ciphertext using RSA-OAEP.
-// If random != nil, DecryptOAEP uses RSA blinding to avoid timing side-channel attacks.
+
+// OAEP is parameterised by a hash function that is used as a random oracle.
+// Encryption and decryption of a given message must use the same hash function
+// and sha256.New() is a reasonable choice.
+//
+// The random parameter, if not nil, is used to blind the private-key operation
+// and avoid timing side-channel attacks. Blinding is purely internal to this
+// function – the random data need not match that used when encrypting.
+//
+// The label parameter must match the value given when encrypting. See
+// EncryptOAEP for details.
 func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err error) {
        if err := checkPub(&priv.PublicKey); err != nil {
                return nil, err
index 4ee1c3a8b2afc6e4be23c041f7b40629a61c1e1b..6902f9a86735800d3d633614310e34eb051a5ee7 100644 (file)
@@ -6,8 +6,10 @@ package rsa
 
 import (
        "bytes"
+       "crypto"
        "crypto/rand"
        "crypto/sha1"
+       "crypto/sha256"
        "math/big"
        "testing"
 )
@@ -127,9 +129,10 @@ func fromBase10(base10 string) *big.Int {
        return i
 }
 
-func BenchmarkRSA2048Decrypt(b *testing.B) {
-       b.StopTimer()
-       priv := &PrivateKey{
+var test2048Key *PrivateKey
+
+func init() {
+       test2048Key = &PrivateKey{
                PublicKey: PublicKey{
                        N: fromBase10("14314132931241006650998084889274020608918049032671858325988396851334124245188214251956198731333464217832226406088020736932173064754214329009979944037640912127943488972644697423190955557435910767690712778463524983667852819010259499695177313115447116110358524558307947613422897787329221478860907963827160223559690523660574329011927531289655711860504630573766609239332569210831325633840174683944553667352219670930408593321661375473885147973879086994006440025257225431977751512374815915392249179976902953721486040787792801849818254465486633791826766873076617116727073077821584676715609985777563958286637185868165868520557"),
                        E: 3,
@@ -140,14 +143,28 @@ func BenchmarkRSA2048Decrypt(b *testing.B) {
                        fromBase10("109348945610485453577574767652527472924289229538286649661240938988020367005475727988253438647560958573506159449538793540472829815903949343191091817779240101054552748665267574271163617694640513549693841337820602726596756351006149518830932261246698766355347898158548465400674856021497190430791824869615170301029"),
                },
        }
-       priv.Precompute()
+       test2048Key.Precompute()
+}
+
+func BenchmarkRSA2048Decrypt(b *testing.B) {
+       b.StopTimer()
 
        c := fromBase10("8472002792838218989464636159316973636630013835787202418124758118372358261975764365740026024610403138425986214991379012696600761514742817632790916315594342398720903716529235119816755589383377471752116975374952783629225022962092351886861518911824745188989071172097120352727368980275252089141512321893536744324822590480751098257559766328893767334861211872318961900897793874075248286439689249972315699410830094164386544311554704755110361048571142336148077772023880664786019636334369759624917224888206329520528064315309519262325023881707530002540634660750469137117568199824615333883758410040459705787022909848740188613313")
 
        b.StartTimer()
 
        for i := 0; i < b.N; i++ {
-               decrypt(nil, priv, c)
+               decrypt(nil, test2048Key, c)
+       }
+}
+
+func BenchmarkRSA2048Sign(b *testing.B) {
+       b.StopTimer()
+       hashed := sha256.Sum256([]byte("testing"))
+       b.StartTimer()
+
+       for i := 0; i < b.N; i++ {
+               SignPKCS1v15(rand.Reader, test2048Key, crypto.SHA256, hashed[:])
        }
 }
 
index a5fed29375243eda07383e11dbb503328faf0bc5..869ffa50bd32af832f68d286967be541c81656b6 100644 (file)
@@ -85,6 +85,8 @@ var cipherSuites = []*cipherSuite{
        {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
        {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
        {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
+       {TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM},
+       {TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
        {TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil},
        {TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
        {TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
@@ -266,6 +268,8 @@ const (
        TLS_RSA_WITH_3DES_EDE_CBC_SHA           uint16 = 0x000a
        TLS_RSA_WITH_AES_128_CBC_SHA            uint16 = 0x002f
        TLS_RSA_WITH_AES_256_CBC_SHA            uint16 = 0x0035
+       TLS_RSA_WITH_AES_128_GCM_SHA256         uint16 = 0x009c
+       TLS_RSA_WITH_AES_256_GCM_SHA384         uint16 = 0x009d
        TLS_ECDHE_ECDSA_WITH_RC4_128_SHA        uint16 = 0xc007
        TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA    uint16 = 0xc009
        TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA    uint16 = 0xc00a
index a3d75d69cbfadf33acc4a6726cd0f340c799f32f..c68ebfe188b41a9609f40cccb4c2c93720e12602 100644 (file)
@@ -255,7 +255,8 @@ type Config struct {
 
        // Certificates contains one or more certificate chains
        // to present to the other side of the connection.
-       // Server configurations must include at least one certificate.
+       // Server configurations must include at least one certificate
+       // or else set GetCertificate.
        Certificates []Certificate
 
        // NameToCertificate maps from a certificate name to an element of
@@ -285,7 +286,8 @@ type Config struct {
 
        // ServerName is used to verify the hostname on the returned
        // certificates unless InsecureSkipVerify is given. It is also included
-       // in the client's handshake to support virtual hosting.
+       // in the client's handshake to support virtual hosting unless it is
+       // an IP address.
        ServerName string
 
        // ClientAuth determines the server's policy for
index e3dcf15400ce18a6c3985ba02239fb013910e78e..03775685fb67919e05ded9a1e4510a4ac2eb60a2 100644 (file)
@@ -16,6 +16,7 @@ import (
        "io"
        "net"
        "sync"
+       "sync/atomic"
        "time"
 )
 
@@ -56,6 +57,11 @@ type Conn struct {
        input    *block       // application data waiting to be read
        hand     bytes.Buffer // handshake data waiting to be read
 
+       // activeCall is an atomic int32; the low bit is whether Close has
+       // been called. the rest of the bits are the number of goroutines
+       // in Conn.Write.
+       activeCall int32
+
        tmp [16]byte
 }
 
@@ -98,12 +104,13 @@ func (c *Conn) SetWriteDeadline(t time.Time) error {
 type halfConn struct {
        sync.Mutex
 
-       err     error       // first permanent error
-       version uint16      // protocol version
-       cipher  interface{} // cipher algorithm
-       mac     macFunction
-       seq     [8]byte // 64-bit sequence number
-       bfree   *block  // list of free blocks
+       err            error       // first permanent error
+       version        uint16      // protocol version
+       cipher         interface{} // cipher algorithm
+       mac            macFunction
+       seq            [8]byte  // 64-bit sequence number
+       bfree          *block   // list of free blocks
+       additionalData [13]byte // to avoid allocs; interface method args escape
 
        nextCipher interface{} // next encryption state
        nextMac    macFunction // next MAC algorithm
@@ -262,14 +269,13 @@ func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert)
                        nonce := payload[:8]
                        payload = payload[8:]
 
-                       var additionalData [13]byte
-                       copy(additionalData[:], hc.seq[:])
-                       copy(additionalData[8:], b.data[:3])
+                       copy(hc.additionalData[:], hc.seq[:])
+                       copy(hc.additionalData[8:], b.data[:3])
                        n := len(payload) - c.Overhead()
-                       additionalData[11] = byte(n >> 8)
-                       additionalData[12] = byte(n)
+                       hc.additionalData[11] = byte(n >> 8)
+                       hc.additionalData[12] = byte(n)
                        var err error
-                       payload, err = c.Open(payload[:0], nonce, payload, additionalData[:])
+                       payload, err = c.Open(payload[:0], nonce, payload, hc.additionalData[:])
                        if err != nil {
                                return false, 0, alertBadRecordMAC
                        }
@@ -378,13 +384,12 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
                        payload := b.data[recordHeaderLen+explicitIVLen:]
                        payload = payload[:payloadLen]
 
-                       var additionalData [13]byte
-                       copy(additionalData[:], hc.seq[:])
-                       copy(additionalData[8:], b.data[:3])
-                       additionalData[11] = byte(payloadLen >> 8)
-                       additionalData[12] = byte(payloadLen)
+                       copy(hc.additionalData[:], hc.seq[:])
+                       copy(hc.additionalData[8:], b.data[:3])
+                       hc.additionalData[11] = byte(payloadLen >> 8)
+                       hc.additionalData[12] = byte(payloadLen)
 
-                       c.Seal(payload[:0], nonce, payload, additionalData[:])
+                       c.Seal(payload[:0], nonce, payload, hc.additionalData[:])
                case cbcMode:
                        blockSize := c.BlockSize()
                        if explicitIVLen > 0 {
@@ -507,6 +512,23 @@ func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) {
        return b, bb
 }
 
+// RecordHeaderError results when a TLS record header is invalid.
+type RecordHeaderError struct {
+       // Msg contains a human readable string that describes the error.
+       Msg string
+       // RecordHeader contains the five bytes of TLS record header that
+       // triggered the error.
+       RecordHeader [5]byte
+}
+
+func (e RecordHeaderError) Error() string { return "tls: " + e.Msg }
+
+func (c *Conn) newRecordHeaderError(msg string) (err RecordHeaderError) {
+       err.Msg = msg
+       copy(err.RecordHeader[:], c.rawInput.data)
+       return err
+}
+
 // readRecord reads the next TLS record from the connection
 // and updates the record layer state.
 // c.in.Mutex <= L; c.input == nil.
@@ -557,18 +579,20 @@ Again:
        // an SSLv2 client.
        if want == recordTypeHandshake && typ == 0x80 {
                c.sendAlert(alertProtocolVersion)
-               return c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received"))
+               return c.in.setErrorLocked(c.newRecordHeaderError("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 c.in.setErrorLocked(fmt.Errorf("tls: received record with version %x when expecting version %x", vers, c.vers))
+               msg := fmt.Sprintf("received record with version %x when expecting version %x", vers, c.vers)
+               return c.in.setErrorLocked(c.newRecordHeaderError(msg))
        }
        if n > maxCiphertext {
                c.sendAlert(alertRecordOverflow)
-               return c.in.setErrorLocked(fmt.Errorf("tls: oversized record received with length %d", n))
+               msg := fmt.Sprintf("oversized record received with length %d", n)
+               return c.in.setErrorLocked(c.newRecordHeaderError(msg))
        }
        if !c.haveVers {
                // First message, be extra suspicious: this might not be a TLS
@@ -577,7 +601,7 @@ Again:
                // it's probably not real.
                if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 {
                        c.sendAlert(alertUnexpectedMessage)
-                       return c.in.setErrorLocked(fmt.Errorf("tls: first record does not look like a TLS handshake"))
+                       return c.in.setErrorLocked(c.newRecordHeaderError("first record does not look like a TLS handshake"))
                }
        }
        if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil {
@@ -837,8 +861,22 @@ func (c *Conn) readHandshake() (interface{}, error) {
        return m, nil
 }
 
+var errClosed = errors.New("crypto/tls: use of closed connection")
+
 // Write writes data to the connection.
 func (c *Conn) Write(b []byte) (int, error) {
+       // interlock with Close below
+       for {
+               x := atomic.LoadInt32(&c.activeCall)
+               if x&1 != 0 {
+                       return 0, errClosed
+               }
+               if atomic.CompareAndSwapInt32(&c.activeCall, x, x+2) {
+                       defer atomic.AddInt32(&c.activeCall, -2)
+                       break
+               }
+       }
+
        if err := c.Handshake(); err != nil {
                return 0, err
        }
@@ -942,6 +980,27 @@ func (c *Conn) Read(b []byte) (n int, err error) {
 
 // Close closes the connection.
 func (c *Conn) Close() error {
+       // Interlock with Conn.Write above.
+       var x int32
+       for {
+               x = atomic.LoadInt32(&c.activeCall)
+               if x&1 != 0 {
+                       return errClosed
+               }
+               if atomic.CompareAndSwapInt32(&c.activeCall, x, x|1) {
+                       break
+               }
+       }
+       if x != 0 {
+               // io.Writer and io.Closer should not be used concurrently.
+               // If Close is called while a Write is currently in-flight,
+               // interpret that as a sign that this Close is really just
+               // being used to break the Write and/or clean up resources and
+               // avoid sending the alertCloseNotify, which may block
+               // waiting on handshakeMutex or the c.out mutex.
+               return c.conn.Close()
+       }
+
        var alertErr error
 
        c.handshakeMutex.Lock()
index 0b591d7309c2592b9067b8ba796519806260e1fd..3c996acf8785b414e8efb630bdca3b6747b05c21 100644 (file)
@@ -49,13 +49,20 @@ func (c *Conn) clientHandshake() error {
                return errors.New("tls: NextProtos values too large")
        }
 
+       sni := c.config.ServerName
+       // IP address literals are not permitted as SNI values. See
+       // https://tools.ietf.org/html/rfc6066#section-3.
+       if net.ParseIP(sni) != nil {
+               sni = ""
+       }
+
        hello := &clientHelloMsg{
                vers:                c.config.maxVersion(),
                compressionMethods:  []uint8{compressionNone},
                random:              make([]byte, 32),
                ocspStapling:        true,
                scts:                true,
-               serverName:          c.config.ServerName,
+               serverName:          sni,
                supportedCurves:     c.config.curvePreferences(),
                supportedPoints:     []uint8{pointFormatUncompressed},
                nextProtoNeg:        len(c.config.NextProtos) > 0,
@@ -158,10 +165,10 @@ NextCipherSuite:
        c.vers = vers
        c.haveVers = true
 
-       suite := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
+       suite := mutualCipherSuite(hello.cipherSuites, serverHello.cipherSuite)
        if suite == nil {
                c.sendAlert(alertHandshakeFailure)
-               return fmt.Errorf("tls: server selected an unsupported cipher suite")
+               return errors.New("tls: server chose an unconfigured cipher suite")
        }
 
        hs := &clientHandshakeState{
index 664fe8de6a0c73b0439cffcc5621955f49c955fd..f78cc4693550f504e55422d7611dce3e097bca46 100644 (file)
@@ -19,6 +19,7 @@ import (
        "os/exec"
        "path/filepath"
        "strconv"
+       "strings"
        "testing"
        "time"
 )
@@ -297,6 +298,22 @@ func TestHandshakeClientRSARC4(t *testing.T) {
        runClientTestTLS12(t, test)
 }
 
+func TestHandshakeClientRSAAES128GCM(t *testing.T) {
+       test := &clientTest{
+               name:    "AES128-GCM-SHA256",
+               command: []string{"openssl", "s_server", "-cipher", "AES128-GCM-SHA256"},
+       }
+       runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientRSAAES256GCM(t *testing.T) {
+       test := &clientTest{
+               name:    "AES256-GCM-SHA384",
+               command: []string{"openssl", "s_server", "-cipher", "AES256-GCM-SHA384"},
+       }
+       runClientTestTLS12(t, test)
+}
+
 func TestHandshakeClientECDHERSAAES(t *testing.T) {
        test := &clientTest{
                name:    "ECDHE-RSA-AES",
@@ -600,3 +617,80 @@ func TestHandshakClientSCTs(t *testing.T) {
        }
        runClientTestTLS12(t, test)
 }
+
+func TestNoIPAddressesInSNI(t *testing.T) {
+       for _, ipLiteral := range []string{"1.2.3.4", "::1"} {
+               c, s := net.Pipe()
+
+               go func() {
+                       client := Client(c, &Config{ServerName: ipLiteral})
+                       client.Handshake()
+               }()
+
+               var header [5]byte
+               if _, err := io.ReadFull(s, header[:]); err != nil {
+                       t.Fatal(err)
+               }
+               recordLen := int(header[3])<<8 | int(header[4])
+
+               record := make([]byte, recordLen)
+               if _, err := io.ReadFull(s, record[:]); err != nil {
+                       t.Fatal(err)
+               }
+               s.Close()
+
+               if bytes.Index(record, []byte(ipLiteral)) != -1 {
+                       t.Errorf("IP literal %q found in ClientHello: %x", ipLiteral, record)
+               }
+       }
+}
+
+func TestServerSelectingUnconfiguredCipherSuite(t *testing.T) {
+       // This checks that the server can't select a cipher suite that the
+       // client didn't offer. See #13174.
+
+       c, s := net.Pipe()
+       errChan := make(chan error, 1)
+
+       go func() {
+               client := Client(c, &Config{
+                       ServerName:   "foo",
+                       CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+               })
+               errChan <- client.Handshake()
+       }()
+
+       var header [5]byte
+       if _, err := io.ReadFull(s, header[:]); err != nil {
+               t.Fatal(err)
+       }
+       recordLen := int(header[3])<<8 | int(header[4])
+
+       record := make([]byte, recordLen)
+       if _, err := io.ReadFull(s, record); err != nil {
+               t.Fatal(err)
+       }
+
+       // Create a ServerHello that selects a different cipher suite than the
+       // sole one that the client offered.
+       serverHello := &serverHelloMsg{
+               vers:        VersionTLS12,
+               random:      make([]byte, 32),
+               cipherSuite: TLS_RSA_WITH_AES_256_GCM_SHA384,
+       }
+       serverHelloBytes := serverHello.marshal()
+
+       s.Write([]byte{
+               byte(recordTypeHandshake),
+               byte(VersionTLS12 >> 8),
+               byte(VersionTLS12 & 0xff),
+               byte(len(serverHelloBytes) >> 8),
+               byte(len(serverHelloBytes)),
+       })
+       s.Write(serverHelloBytes)
+       s.Close()
+
+       if err := <-errChan; !strings.Contains(err.Error(), "unconfigured cipher") {
+               t.Fatalf("Expected error about unconfigured cipher suite but got %q", err)
+       }
+}
index 799a776799aa1c158562f7e68a5712d0d68a6641..111ce53487a79116cc88f74d3afe2c47a5b0133e 100644 (file)
@@ -763,6 +763,10 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
                                return false
                        }
                        d = d[1:]
+                       if len(d) == 0 {
+                               // ALPN protocols must not be empty.
+                               return false
+                       }
                        m.alpnProtocol = string(d)
                case extensionSCT:
                        d := data[:length]
index 20c2bd6d4d4fbbc9ae1f6bb27b28299805072821..438fb3140a32cbb923204a8ef26d6f28b66c70a4 100644 (file)
@@ -84,7 +84,7 @@ func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessa
        s.Close()
        if len(expectedSubStr) == 0 {
                if err != nil && err != io.EOF {
-                       t.Errorf("Got error: %s; expected to succeed", err, expectedSubStr)
+                       t.Errorf("Got error: %s; expected to succeed", err)
                }
        } else if err == nil || !strings.Contains(err.Error(), expectedSubStr) {
                t.Errorf("Got error: %s; expected to match substring '%s'", err, expectedSubStr)
index 6127c1ccfe79facc2484f70977d926377bff993c..747b817ba32f0336b664a8c7374c5ca7302b0a09 100644 (file)
@@ -145,11 +145,12 @@ func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, labe
 // masterFromPreMasterSecret generates the master secret from the pre-master
 // secret. See http://tools.ietf.org/html/rfc5246#section-8.1
 func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte {
-       var seed [tlsRandomLength * 2]byte
-       copy(seed[0:len(clientRandom)], clientRandom)
-       copy(seed[len(clientRandom):], serverRandom)
+       seed := make([]byte, 0, len(clientRandom)+len(serverRandom))
+       seed = append(seed, clientRandom...)
+       seed = append(seed, serverRandom...)
+
        masterSecret := make([]byte, masterSecretLength)
-       prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
+       prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed)
        return masterSecret
 }
 
@@ -157,13 +158,13 @@ func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecr
 // secret, given the lengths of the MAC key, cipher key and IV, as defined in
 // RFC 2246, section 6.3.
 func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
-       var seed [tlsRandomLength * 2]byte
-       copy(seed[0:len(clientRandom)], serverRandom)
-       copy(seed[len(serverRandom):], clientRandom)
+       seed := make([]byte, 0, len(serverRandom)+len(clientRandom))
+       seed = append(seed, serverRandom...)
+       seed = append(seed, clientRandom...)
 
        n := 2*macLen + 2*keyLen + 2*ivLen
        keyMaterial := make([]byte, n)
-       prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
+       prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed)
        clientMAC = keyMaterial[:macLen]
        keyMaterial = keyMaterial[macLen:]
        serverMAC = keyMaterial[:macLen]
index 4bad7865df3f7bc411a17a54c9c02452e814c9ef..a62d27d5e3dead7eef91bd849fda4b859e894319 100644 (file)
@@ -1,19 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 59 02 00 00  55 03 01 c0 e1 5c 5b 45  |....Y...U....\[E|
-00000010  70 fc a1 73 44 e7 69 b6  83 a1 71 bc 03 21 2e cc  |p..sD.i...q..!..|
-00000020  21 7a 28 20 82 6b 2f 77  7d 40 c7 20 0d e4 19 db  |!z( .k/w}@. ....|
-00000030  35 cd 75 a4 e7 e5 6c 3e  c9 d5 fe 9d c5 88 78 7b  |5.u...l>......x{|
-00000040  c4 fc 04 9a c1 10 7a 15  d9 e9 4a 95 c0 09 00 00  |......z...J.....|
+00000000  16 03 01 00 59 02 00 00  55 03 01 38 1a 94 8d 84  |....Y...U..8....|
+00000010  d7 a4 29 89 50 ad 07 97  5b c0 2c 7b 8c a6 75 0e  |..).P...[.,{..u.|
+00000020  97 51 62 10 07 87 c5 6f  0a 5f 86 20 1d ac 1d 05  |.Qb....o._. ....|
+00000030  ea 85 48 84 73 d9 07 8d  d0 81 56 99 81 10 7b 18  |..H.s.....V...{.|
+00000040  e8 5e da a9 fe cd f9 91  88 31 9b 6e c0 09 00 00  |.^.......1.n....|
 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....|
 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 d6 0c 00  00 d2 03 00 17 41 04 01  |*............A..|
-00000280  74 83 af 3a 65 7a ad 1a  63 1f 13 82 9d f4 de 06  |t..:ez..c.......|
-00000290  4e 3a 03 81 61 72 ff f8  58 da 7b f5 81 6d 81 57  |N:..ar..X.{..m.W|
-000002a0  d9 d1 b1 6d e3 97 db 86  72 17 15 18 16 d4 ec 04  |...m....r.......|
-000002b0  32 7c 38 90 6b a4 3c e9  35 79 2d 4c 39 5e 2d 00  |2|8.k.<.5y-L9^-.|
-000002c0  8b 30 81 88 02 42 01 44  78 e1 2a bb 95 f7 45 58  |.0...B.Dx.*...EX|
-000002d0  d4 0d b6 e4 4e ff 48 b3  11 14 ee d5 6c bb 5f 0c  |....N.H.....l._.|
-000002e0  90 b6 ef bc 05 77 f6 05  42 b4 d8 a6 70 e6 8c 90  |.....w..B...p...|
-000002f0  f0 4b 3b c9 d3 4e 0c 85  65 b4 e0 fe b5 10 09 9b  |.K;..N..e.......|
-00000300  e1 08 84 ea 93 96 8e a4  02 42 01 c7 15 ee 9d 98  |.........B......|
-00000310  b7 25 eb 07 ff f6 94 7e  e7 9d a5 17 9e 37 93 40  |.%.....~.....7.@|
-00000320  4c 9f eb 6b a3 7a 57 d8  81 c6 d9 09 34 aa 96 8c  |L..k.zW.....4...|
-00000330  4d 28 2e 9f f7 0b 1c 09  e1 d1 d8 48 6e 8a 8e 9c  |M(.........Hn...|
-00000340  01 4c e7 2d 53 8f 8e 71  61 82 ff ff 16 03 01 00  |.L.-S..qa.......|
-00000350  0e 0d 00 00 06 03 01 02  40 00 00 0e 00 00 00     |........@......|
+00000270  2a 16 03 01 00 d5 0c 00  00 d1 03 00 17 41 04 68  |*............A.h|
+00000280  37 18 3d 57 d2 5a 39 75  1e 7f 0a 3a 47 65 36 2e  |7.=W.Z9u...:Ge6.|
+00000290  6d cb 8f aa 0f 0d 45 5e  3f 14 82 f5 8c b1 11 0a  |m.....E^?.......|
+000002a0  8f e0 bc e4 07 d3 d5 bf  2d f4 82 ba cf c9 1c 88  |........-.......|
+000002b0  33 72 a8 49 39 48 40 74  c6 96 c3 30 72 31 34 00  |3r.I9H@t...0r14.|
+000002c0  8a 30 81 87 02 41 0e 43  2d 29 81 e9 c3 07 fc 5c  |.0...A.C-).....\|
+000002d0  ad c0 51 9e 0f cf c5 77  e4 bf 00 b6 66 f9 0e c6  |..Q....w....f...|
+000002e0  40 c6 b5 49 a4 04 05 31  2c 7c 1f 24 38 80 1b 3f  |@..I...1,|.$8..?|
+000002f0  16 5f c7 4d a8 7d 98 50  7f 7d 6d ed e9 19 1d 19  |._.M.}.P.}m.....|
+00000300  7b fd ec c5 4d 18 ab 02  42 01 00 db 37 b7 fa 39  |{...M...B...7..9|
+00000310  4b 3f 16 06 eb b8 4a 22  c6 de 00 d8 a7 eb a2 9e  |K?....J"........|
+00000320  e1 6f f4 a4 32 e2 ca d0  72 3a e5 f3 14 27 a0 dd  |.o..2...r:...'..|
+00000330  c4 26 34 b3 6c a3 d0 03  90 7a 2e 0e bf 0b 63 63  |.&4.l....z....cc|
+00000340  77 66 37 dd 1a 0f 7a 90  3f c8 a9 16 03 01 00 0e  |wf7...z.?.......|
+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|
 00000010  82 01 fc 30 82 01 5e 02  09 00 9a 30 84 6c 26 35  |...0..^....0.l&5|
 00000220  51 88 35 75 71 b5 e5 54  5b 12 2e 8f 09 67 fd a7  |Q.5uq..T[....g..|
 00000230  24 20 3e b2 56 1c ce 97  28 5e f8 2b 2d 4f 9e f1  |$ >.V...(^.+-O..|
 00000240  07 9f 6c 4b 5b 83 56 e2  32 42 e9 58 b6 d7 49 a6  |..lK[.V.2B.X..I.|
-00000250  b5 68 1a 41 03 56 6b dc  5a 89 16 03 01 00 91 0f  |.h.A.Vk.Z.......|
-00000260  00 00 8d 00 8b 30 81 88  02 42 01 91 2d e9 99 a4  |.....0...B..-...|
-00000270  88 5c 03 9c ea 8b 64 07  f2 c9 e7 ad 5b a3 fb 27  |.\....d.....[..'|
-00000280  fd 19 9b 78 bd 7b 9d 0a  cc 8a 61 c5 83 33 02 29  |...x.{....a..3.)|
-00000290  c3 66 24 9d 5f bc 03 d9  2a 49 aa 59 51 83 49 72  |.f$._...*I.YQ.Ir|
-000002a0  13 be ea 82 5a 5c 09 2f  da 23 bc 18 02 42 01 0d  |....Z\./.#...B..|
-000002b0  a1 15 4d fe 18 ec 90 d5  4e 9a 75 60 05 67 10 5e  |..M.....N.u`.g.^|
-000002c0  3c 34 00 e8 18 33 8f 90  26 2e d3 a9 81 6c 43 17  |<4...3..&....lC.|
-000002d0  80 9e c5 bd 23 c9 24 96  a1 29 23 a4 13 3f ad d2  |....#.$..)#..?..|
-000002e0  45 19 0b 56 56 4b c1 f1  cc 70 c8 af 44 ff 34 96  |E..VVK...p..D.4.|
-000002f0  14 03 01 00 01 01 16 03  01 00 30 c4 0c 67 53 06  |..........0..gS.|
-00000300  49 b3 c9 5c 2e 72 f6 54  ba ad ac a8 80 55 17 01  |I..\.r.T.....U..|
-00000310  5c 44 71 7d ad 15 34 95  9a 7f 7b 95 0e 08 70 ce  |\Dq}..4...{...p.|
-00000320  5a 33 f4 3b 4e 80 06 43  70 93 17                 |Z3.;N..Cp..|
+00000250  b5 68 1a 41 03 56 6b dc  5a 89 16 03 01 00 90 0f  |.h.A.Vk.Z.......|
+00000260  00 00 8c 00 8a 30 81 87  02 41 51 c5 53 a8 0f cb  |.....0...AQ.S...|
+00000270  18 79 4a 59 53 62 17 bb  29 39 fa cd 56 6c 5c 29  |.yJYSb..)9..Vl\)|
+00000280  1f e3 bc df fb 9a 29 fa  38 1a 73 aa 4c 79 6b 1c  |......).8.s.Lyk.|
+00000290  9f 1c 8e 95 c7 11 cc df  5d e9 c7 93 ce a3 9b e6  |........].......|
+000002a0  94 17 24 3a 8e f8 9a a9  46 01 f9 02 42 01 a1 df  |..$:....F...B...|
+000002b0  c5 cc fe 8d 5b 34 fb 89  2f f5 b3 3f 75 d7 19 1b  |....[4../..?u...|
+000002c0  5e 0f 1a 2e 8f 2d 62 61  73 85 2c 03 3b 22 07 2f  |^....-bas.,.;"./|
+000002d0  6b f3 5c fb ba b2 87 54  1c ef d2 f8 82 f3 9e f8  |k.\....T........|
+000002e0  ce 1b fa ce b0 6d d0 85  f8 62 6e d6 ba 93 cc 14  |.....m...bn.....|
+000002f0  03 01 00 01 01 16 03 01  00 30 76 90 a8 a2 8d 25  |.........0v....%|
+00000300  c5 c2 ff ef 2b 76 83 2c  7a 0d 44 37 99 67 02 d3  |....+v.,z.D7.g..|
+00000310  6e 3b 28 83 21 cf f5 6a  71 61 2d 5b 24 57 b2 19  |n;(.!..jqa-[$W..|
+00000320  63 d4 e5 96 0c 0c e1 f3  3a 99                    |c.......:.|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 3b ba 6c 73 ec  |..........0;.ls.|
-00000010  11 5b 44 46 1d bb 31 1b  1b e8 d8 51 4f 95 b0 40  |.[DF..1....QO..@|
-00000020  87 49 33 73 40 98 61 1c  94 02 48 9b 80 d3 6c af  |.I3s@.a...H...l.|
-00000030  e2 31 63 11 a7 c8 db ed  7a a4 4d                 |.1c.....z.M|
+00000000  14 03 01 00 01 01 16 03  01 00 30 37 f0 ad 4c 11  |..........07..L.|
+00000010  6d fb 54 90 13 d2 10 93  43 d8 be 3b d0 2b 14 a5  |m.T.....C..;.+..|
+00000020  9d fb a6 5d 38 e0 f5 e9  a6 0a 8e 3d 99 a2 ec 96  |...]8......=....|
+00000030  d8 ff 90 13 03 99 33 d7  15 29 5f                 |......3..)_|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 20 2e f7 66  f0 ce 50 d7 38 7a d4 fd  |.... ..f..P.8z..|
-00000010  e3 66 b1 76 76 59 ad bc  b0 0a 75 1d f0 92 6e e3  |.f.vvY....u...n.|
-00000020  21 1d 13 dc ad 17 03 01  00 20 f1 b2 0f 3b 26 91  |!........ ...;&.|
-00000030  ed ff 9f fc 41 04 7e 47  17 02 af 0c 2b e8 b7 31  |....A.~G....+..1|
-00000040  ae 29 71 f9 a8 89 84 f3  e8 da 15 03 01 00 20 1f  |.)q........... .|
-00000050  26 64 cf 34 c1 48 6b 79  61 e2 77 57 9d 27 14 45  |&d.4.Hkya.wW.'.E|
-00000060  46 24 ad 2d 35 57 db 2b  32 03 e2 68 b0 1a 5a     |F$.-5W.+2..h..Z|
+00000000  17 03 01 00 20 f9 59 b0  e2 8b f9 2c dd 30 1b 8f  |.... .Y....,.0..|
+00000010  df 85 0f 17 88 23 5e ca  c9 d3 ca 5f 52 d4 33 e0  |.....#^...._R.3.|
+00000020  d2 62 54 17 f2 17 03 01  00 20 62 2d 28 d2 55 68  |.bT...... b-(.Uh|
+00000030  77 ab 6e c0 ac d9 cd 31  1c 38 aa 07 b3 e8 0d 89  |w.n....1.8......|
+00000040  7e e4 f3 a0 65 84 f6 b8  c8 91 15 03 01 00 20 b5  |~...e......... .|
+00000050  95 69 90 d7 32 d1 5a a5  e0 e2 6c 0a dc 00 1c 5e  |.i..2.Z...l....^|
+00000060  d2 10 2b a2 3e ae a5 b2  63 9f c4 4e 62 56 db     |..+.>...c..NbV.|
index 0e420a64804d14bf9c24683919ae981eeb4b1eb2..298cbe1df533dbb965dd8915e6617d56130d7167 100644 (file)
@@ -1,65 +1,60 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 51 02 00 00  4d 03 01 b7 de 52 5a 07  |....Q...M....RZ.|
-00000010  43 b8 72 1d d9 6f 5c a5  70 da ee 27 b7 a9 50 9d  |C.r..o\.p..'..P.|
-00000020  e7 75 ad 61 a5 2f 69 47  2a d8 2e 20 a8 b0 64 6b  |.u.a./iG*.. ..dk|
-00000030  4d 25 ec 50 2b 8e a7 9b  0c f9 f5 3c 62 96 a3 53  |M%.P+......<b..S|
-00000040  a7 4b af 33 1e e7 f8 43  b9 be 6e e7 00 05 00 00  |.K.3...C..n.....|
-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..|
-00000080  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000090  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-000000a0  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-000000b0  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000c0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000d0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000e0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000f0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-00000100  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-00000110  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000120  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000130  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000140  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000150  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000160  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000170  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000180  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000190  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-000001a0  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-000001b0  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001c0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001d0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001e0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001f0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-00000200  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-00000210  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000220  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000230  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000240  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000250  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000260  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000270  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000280  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000290  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-000002a0  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-000002b0  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002c0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002d0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002e0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002f0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-00000300  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 01 00 0e 0d 00  |n8P)l...........|
-00000320  00 06 03 01 02 40 00 00  0e 00 00 00              |.....@......|
+00000000  16 03 01 00 51 02 00 00  4d 03 01 4e 15 d3 06 f6  |....Q...M..N....|
+00000010  ec 13 16 c5 fa 59 cf 5e  2f ad 85 b9 38 e7 7f fb  |.....Y.^/...8...|
+00000020  85 cb da eb f2 2e 17 51  a2 b0 be 20 61 e4 32 c9  |.......Q... a.2.|
+00000030  66 92 36 89 0c 0c f4 00  15 47 86 d9 e9 90 ab 2d  |f.6......G.....-|
+00000040  8f a3 e2 5e f6 44 2c 6a  1d 98 88 5c 00 05 00 00  |...^.D,j...\....|
+00000050  05 ff 01 00 01 00 16 03  01 02 71 0b 00 02 6d 00  |..........q...m.|
+00000060  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000070  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000080  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000090  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+000000a0  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+000000b0  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000c0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000d0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000e0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000f0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+00000100  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+00000110  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000120  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000130  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000140  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000150  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000160  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000170  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000180  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000190  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+000001a0  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+000001b0  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001c0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001d0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001e0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001f0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+00000200  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+00000210  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f..@....xH.A0.|
+00000220  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000230  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000240  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000250  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H@.-.....|
+00000260  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000270  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000280  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000290  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+000002a0  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+000002b0  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002c0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 01 00  |..A4......9.....|
+000002d0  0e 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|
 00000010  82 01 fc 30 82 01 5e 02  09 00 9a 30 84 6c 26 35  |...0..^....0.l&5|
 000001e0  be e8 91 b3 da 1a f5 5d  a3 23 f5 26 8b 45 70 8d  |.......].#.&.Ep.|
 000001f0  65 62 9b 7e 01 99 3d 18  f6 10 9a 38 61 9b 2e 57  |eb.~..=....8a..W|
 00000200  e4 fa cc b1 8a ce e2 23  a0 87 f0 e1 67 51 eb 16  |.......#....gQ..|
-00000210  03 01 00 86 10 00 00 82  00 80 6d 51 f3 7f f9 3e  |..........mQ...>|
-00000220  fb 75 82 41 36 83 e8 6a  ee 2a 2e 25 90 67 4c 8e  |.u.A6..j.*.%.gL.|
-00000230  62 2f 30 81 17 e0 85 09  0c 2b b7 23 d7 b0 e2 1d  |b/0......+.#....|
-00000240  f7 3b d7 f5 a1 27 b6 ee  24 b6 1b cc 5b ea 66 0d  |.;...'..$...[.f.|
-00000250  6a f4 e5 85 f9 da 43 b4  0e 86 85 e1 f5 aa be c8  |j.....C.........|
-00000260  ce 39 4c 9c 86 00 08 c2  4b e2 c6 ec 2f f7 ce e6  |.9L.....K.../...|
-00000270  bd 77 82 6f 23 b6 e0 bd  a2 92 b7 3a ac e8 56 f1  |.w.o#......:..V.|
-00000280  af 54 5e 46 87 e9 3b 33  e7 b8 28 b7 d6 c8 90 35  |.T^F..;3..(....5|
-00000290  d4 1c 43 d1 30 6f 55 4e  0a 70 16 03 01 00 91 0f  |..C.0oUN.p......|
-000002a0  00 00 8d 00 8b 30 81 88  02 42 00 b5 1a 9d 48 90  |.....0...B....H.|
-000002b0  2f d9 1a 04 66 f7 3b 4d  d7 ae d9 1e dd 3c fa 24  |/...f.;M.....<.$|
-000002c0  0f 24 97 b2 61 46 16 d9  a0 35 f9 f7 54 45 92 fd  |.$..aF...5..TE..|
-000002d0  10 56 ab 26 d7 b5 10 80  8b 88 95 ef c6 73 1c d2  |.V.&.........s..|
-000002e0  ff e9 20 cd 18 a8 40 c4  4d 83 c2 e2 02 42 01 8c  |.. ...@.M....B..|
-000002f0  d2 13 4c cc e5 38 37 17  6c 83 d6 ad c1 dc af ec  |..L..87.l.......|
-00000300  8d 06 75 b8 08 ad 56 4a  8f b9 03 59 80 f8 81 d4  |..u...VJ...Y....|
-00000310  f3 91 89 eb 9c 27 5d e1  dc 6d ef d6 20 da e7 9c  |.....']..m.. ...|
-00000320  71 75 cb 2a f9 e4 05 46  c8 85 ca 7b 9c 97 e8 6d  |qu.*...F...{...m|
-00000330  14 03 01 00 01 01 16 03  01 00 24 9f 67 4e 22 04  |..........$.gN".|
-00000340  10 f4 28 55 3e 50 88 90  61 07 42 29 f5 9b f5 32  |..(U>P..a.B)...2|
-00000350  16 3d ea c1 8f aa a1 4c  b5 72 26 d8 32 cd 50     |.=.....L.r&.2.P|
+00000210  03 01 00 86 10 00 00 82  00 80 73 bd 73 65 92 86  |..........s.se..|
+00000220  23 41 14 79 7f d5 c1 10  ce 94 4d ad 9c c3 a9 87  |#A.y......M.....|
+00000230  b5 32 52 f8 6b 11 93 2d  9b 98 0b 8b 1d c0 f6 53  |.2R.k..-.......S|
+00000240  17 6d c7 9c 2e ae c9 6f  cc 99 23 38 37 1a 10 fe  |.m.....o..#87...|
+00000250  05 0b b5 55 0a 14 e9 60  7d 70 26 98 e2 54 d9 65  |...U...`}p&..T.e|
+00000260  cf 2e f4 53 5f 1d aa 3a  f6 33 7b eb 4c 0e b3 ff  |...S_..:.3{.L...|
+00000270  5a db 36 2a 47 f3 df f9  fc f5 31 78 83 aa 6b 52  |Z.6*G.....1x..kR|
+00000280  b7 ba 1a 96 bc fa c1 a1  a9 bb 2b f5 38 89 00 4d  |..........+.8..M|
+00000290  e5 78 13 4e a4 38 46 42  dc 16 16 03 01 00 91 0f  |.x.N.8FB........|
+000002a0  00 00 8d 00 8b 30 81 88  02 42 01 45 b9 8f b1 1f  |.....0...B.E....|
+000002b0  72 80 2c 4f 2c 65 58 db  40 7e f1 d5 14 0b cc 4c  |r.,O,eX.@~.....L|
+000002c0  8b 50 5c ee 93 45 95 3d  fe 00 5e 5e ca 13 56 8d  |.P\..E.=..^^..V.|
+000002d0  2b b3 1a 22 70 3f d2 41  cf 74 8f c3 0f 37 ba 97  |+.."p?.A.t...7..|
+000002e0  cb 29 16 77 92 df 19 35  f9 8a a0 8e 02 42 01 00  |.).w...5.....B..|
+000002f0  3f 8b ce b1 2a 01 43 e8  2c b5 27 d1 19 bc 04 b3  |?...*.C.,.'.....|
+00000300  c3 ad bf e8 12 37 57 6f  c9 01 7c 8e f4 4d 88 39  |.....7Wo..|..M.9|
+00000310  4b 00 f6 ff fd 38 39 f8  3e 7f 49 d4 6a 82 94 6a  |K....89.>.I.j..j|
+00000320  d3 f4 17 f2 a9 e0 ef 85  1e 01 85 b6 ca 89 91 ee  |................|
+00000330  14 03 01 00 01 01 16 03  01 00 24 8d 82 24 82 55  |..........$..$.U|
+00000340  c4 0e 45 8c f0 f3 e3 29  4e ff 6c ee 43 4b ca 68  |..E....)N.l.CK.h|
+00000350  2e 12 98 cf ce b6 7e fa  73 07 e1 0f aa 7f 80     |......~.s......|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 24 df 8d f1 07 6d  |..........$....m|
-00000010  63 39 fc ba b1 67 3b 68  85 b9 37 7d d3 67 19 76  |c9...g;h..7}.g.v|
-00000020  34 a4 1b 86 31 bd fe 06  72 00 d8 2b f2 65 3d     |4...1...r..+.e=|
+00000000  14 03 01 00 01 01 16 03  01 00 24 21 a3 eb a6 f5  |..........$!....|
+00000010  d0 17 38 9b 89 ec f3 39  23 33 f6 49 51 41 97 92  |..8....9#3.IQA..|
+00000020  a6 64 bd 60 68 9d 0e 45  06 2f dd ff 79 b6 50     |.d.`h..E./..y.P|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 1a 60 cc 81  4f 8b 73 b3 7f 34 bf f1  |.....`..O.s..4..|
-00000010  7c d8 32 0a ef 2a 26 f9  b8 69 84 83 48 21 ee 15  ||.2..*&..i..H!..|
-00000020  03 01 00 16 23 7a 0c 65  3a 66 1a 75 03 e4 85 3f  |....#z.e:f.u...?|
-00000030  83 cd 55 70 99 f4 44 dc  67 ba                    |..Up..D.g.|
+00000000  17 03 01 00 1a d2 72 d5  91 9d fc 6c 22 02 cc 32  |......r....l"..2|
+00000010  58 5c 8a f6 75 11 48 e1  3f e4 e5 81 29 63 62 15  |X\..u.H.?...)cb.|
+00000020  03 01 00 16 b6 9a 1f 43  d4 ae b7 16 25 ce ae b7  |.......C....%...|
+00000030  6c 37 f7 35 0a 26 7d ea  1f 80                    |l7.5.&}...|
index 7e33edc18975e95cc699dc6d98156181d6c255a4..ba4976df3b68f06cbf6b2c94f7dc5f7b401c8599 100644 (file)
@@ -1,19 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 59 02 00 00  55 03 01 dc a9 22 c2 a2  |....Y...U...."..|
-00000010  05 ba c4 66 9a 71 aa 0f  92 6a fc df b0 29 4d 36  |...f.q...j...)M6|
-00000020  39 2e f8 39 ed 8e f6 7f  8f 17 13 20 f8 9c f3 3d  |9..9....... ...=|
-00000030  0a 41 8f 30 c7 5d cd 17  c5 ad 1c 52 45 a3 47 8c  |.A.0.].....RE.G.|
-00000040  07 4c 48 e1 00 2b 32 38  01 c8 79 b7 c0 09 00 00  |.LH..+28..y.....|
+00000000  16 03 01 00 59 02 00 00  55 03 01 eb ed 76 6a 07  |....Y...U....vj.|
+00000010  65 02 ec 6f 93 a0 38 21  09 0d d7 bf 11 20 51 eb  |e..o..8!..... Q.|
+00000020  cc 00 08 9b 7a 98 c4 c5  02 ff c1 20 f9 1b c7 66  |....z...... ...f|
+00000030  35 40 8c 67 8d 7f d5 c8  28 f0 cb d2 f9 da af 7a  |5@.g....(......z|
+00000040  ea 4e 42 f2 5d 44 1c cc  92 36 b1 10 c0 09 00 00  |.NB.]D...6......|
 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....|
 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 89  |*............A..|
-00000280  95 9a 90 82 59 ab 29 bf  10 06 8c 6c 0d 67 cf b1  |....Y.)....l.g..|
-00000290  66 8b 5e 43 b8 46 56 3a  8d 30 92 35 28 82 f2 38  |f.^C.FV:.0.5(..8|
-000002a0  6e 19 5d 37 f0 ab fc 78  15 6a 6a 73 ca dc a6 f2  |n.]7...x.jjs....|
-000002b0  68 5d b3 ab 6d 68 44 3b  80 d2 d9 cd 78 0a ed 00  |h]..mhD;....x...|
-000002c0  8a 30 81 87 02 42 01 80  63 4a 22 4c 8e 66 4e 25  |.0...B..cJ"L.fN%|
-000002d0  e1 86 27 81 de eb b3 a0  c4 dc dc e2 a0 94 2a b6  |..'...........*.|
-000002e0  b3 e9 e7 42 e1 1d 1a c0  43 8d a1 d6 8d 77 84 06  |...B....C....w..|
-000002f0  ba 95 99 e3 54 80 59 4e  3c fb 0c f3 b7 d3 a8 d2  |....T.YN<.......|
-00000300  ce 49 97 fb e2 79 91 93  02 41 2b 2c b7 9f 81 ea  |.I...y...A+,....|
-00000310  de 17 12 af 4d 20 bc a1  43 1d 60 a0 37 52 a2 7b  |....M ..C.`.7R.{|
-00000320  a8 4c de fd 1d fe 37 3b  00 23 61 ce d2 80 47 43  |.L....7;.#a...GC|
-00000330  b0 3a f3 1f aa c7 07 b1  68 5b d8 f3 03 a9 56 5c  |.:......h[....V\|
-00000340  63 ef 83 1d 9c 9c 8d 29  81 e9 3b 16 03 01 00 0e  |c......)..;.....|
+00000270  2a 16 03 01 00 d5 0c 00  00 d1 03 00 17 41 04 34  |*............A.4|
+00000280  47 57 64 b3 20 6d eb 17  9c 36 d4 aa 78 8b 20 26  |GWd. m...6..x. &|
+00000290  6f 22 10 79 5f 96 69 62  1d ae 9f c7 40 17 1e 30  |o".y_.ib....@..0|
+000002a0  10 db d1 13 51 d8 63 61  ef 8e fb 34 d6 02 95 ac  |....Q.ca...4....|
+000002b0  fb 33 72 a9 46 ff 27 b1  15 ca dd 81 8f 5a 58 00  |.3r.F.'......ZX.|
+000002c0  8a 30 81 87 02 41 5c 09  1a 87 40 f3 1a 87 84 31  |.0...A\...@....1|
+000002d0  62 6c e5 a5 c0 3c cc ba  5d 4a 5e 65 ea e0 60 83  |bl...<..]J^e..`.|
+000002e0  fe fe 99 1d 66 4a bb 6c  0d 5e 25 64 e3 92 ce eb  |....fJ.l.^%d....|
+000002f0  15 39 42 a6 b0 98 a1 d3  79 65 c7 fc e7 c7 64 c7  |.9B.....ye....d.|
+00000300  69 9c 2f 7e 00 c1 a3 02  42 01 f2 61 91 ae 8e f6  |i./~....B..a....|
+00000310  88 99 70 55 32 4a fe 08  31 f0 8d d6 e6 1d fa a1  |..pU2J..1.......|
+00000320  76 b6 16 98 58 8e 46 30  b1 00 b6 dd 5d 70 bb e1  |v...X.F0....]p..|
+00000330  81 89 bd aa ac b5 7f 9b  d3 c0 8b 4b c3 36 00 87  |...........K.6..|
+00000340  47 0c 34 92 27 c3 aa bd  0d 7c 36 16 03 01 00 0e  |G.4.'....|6.....|
 00000350  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|
 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 0e 80  9c 3a 6e 40 51 09 39 d4  |.........:n@Q.9.|
-00000260  40 58 10 da 7f 32 12 08  9e f0 4d 9a d7 20 a2 9c  |@X...2....M.. ..|
-00000270  b0 95 3a 33 4e f8 b1 a3  74 62 ab 51 7d 23 d4 32  |..:3N...tb.Q}#.2|
-00000280  a2 af b8 5a 3b b0 23 e4  7a f1 eb 4d b7 bb 23 d5  |...Z;.#.z..M..#.|
-00000290  a9 0d b4 81 d2 b4 45 bd  15 52 ad 58 da 92 a2 c4  |......E..R.X....|
-000002a0  30 66 87 f2 ae c5 e4 8c  fa ba a0 40 76 b8 3f 72  |0f.........@v.?r|
-000002b0  2a d9 95 2a 2d c6 05 3c  1e 2f 11 ef c5 3c 11 e4  |*..*-..<./...<..|
-000002c0  be 5a de 37 43 7f 74 52  6e ee 3c 39 cc f1 14 05  |.Z.7C.tRn.<9....|
-000002d0  2d 91 c2 3d c4 7c 14 03  01 00 01 01 16 03 01 00  |-..=.|..........|
-000002e0  30 cd 3c 92 f8 b9 36 7a  e7 8a fb 0f 2f b8 2c 7b  |0.<...6z..../.,{|
-000002f0  10 59 45 14 0a b0 6a 8c  31 b2 89 5b ac 19 dc 12  |.YE...j.1..[....|
-00000300  73 8c 8c 10 49 5a bf 9f  bc 58 82 32 11 ba c5 38  |s...IZ...X.2...8|
-00000310  ff                                                |.|
+00000250  0f 00 00 82 00 80 1e 4d  89 4e e2 82 ca 5d 31 8a  |.......M.N...]1.|
+00000260  66 c7 c2 d6 00 4d 2e 1e  94 34 61 6b 86 3d 78 60  |f....M...4ak.=x`|
+00000270  70 e1 71 93 22 df 5d 81  d3 d7 33 10 f5 01 f9 1d  |p.q.".]...3.....|
+00000280  e2 4a 91 22 67 ae 5b 2f  4c d9 43 31 35 c6 01 ad  |.J."g.[/L.C15...|
+00000290  59 86 03 a1 9b c5 ea a5  2d aa ef 46 5a a8 70 57  |Y.......-..FZ.pW|
+000002a0  50 59 ea 7a 07 32 bb a6  a1 11 33 05 d8 88 2e 42  |PY.z.2....3....B|
+000002b0  d8 7b f7 34 be 5e 5f 42  9f 6a 90 ed d7 4b c4 7e  |.{.4.^_B.j...K.~|
+000002c0  f9 5c a5 ff 28 f8 a1 f1  8f 1c e0 7a 37 a0 49 e5  |.\..(......z7.I.|
+000002d0  ce 11 46 ef 5f 06 14 03  01 00 01 01 16 03 01 00  |..F._...........|
+000002e0  30 cb 08 f0 3c d4 21 f2  3a 7d db 59 75 80 48 24  |0...<.!.:}.Yu.H$|
+000002f0  27 6f 2c 26 50 a4 7d 6c  91 d5 5d f7 c9 b4 bd 15  |'o,&P.}l..].....|
+00000300  a8 8a 12 d5 40 8c 9a 0f  56 67 66 89 dd 12 36 d8  |....@...Vgf...6.|
+00000310  d3                                                |.|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 da 45 99 fe 52  |..........0.E..R|
-00000010  4f cd d0 e6 30 19 f4 bd  80 6d 5c 8a 72 03 d3 88  |O...0....m\.r...|
-00000020  38 63 e9 c9 39 ee ab 3f  52 26 84 b0 4d cb 5c a4  |8c..9..?R&..M.\.|
-00000030  0d 51 c7 47 48 43 3a bf  89 c7 13                 |.Q.GHC:....|
+00000000  14 03 01 00 01 01 16 03  01 00 30 02 e3 be 9d 2d  |..........0....-|
+00000010  6f 2c 9a b7 b4 f1 a5 30  ec 3e ae 05 e6 02 19 2f  |o,.....0.>...../|
+00000020  a4 ac d1 6e ac de 75 4e  cc 14 e6 78 5a ea 27 7f  |...n..uN...xZ.'.|
+00000030  4e 45 c4 9d b2 da a6 ea  b7 d2 7e                 |NE........~|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 20 4d d9 1d  0d 3d 8b 73 91 b9 4e 5e  |.... M...=.s..N^|
-00000010  35 71 4f 67 79 d2 f7 39  35 ea 23 d0 6d 64 de a5  |5qOgy..95.#.md..|
-00000020  59 fb 75 1f c9 17 03 01  00 20 ba bd 3c b4 d7 be  |Y.u...... ..<...|
-00000030  24 64 68 1e 8c b2 bf 6f  78 9f ad 7f fa dd 89 a6  |$dh....ox.......|
-00000040  f9 e7 5e 70 db e9 db 3a  62 b2 15 03 01 00 20 2a  |..^p...:b..... *|
-00000050  82 f4 8b 45 fc 76 35 6c  54 48 62 2f 52 55 f2 d9  |...E.v5lTHb/RU..|
-00000060  99 b2 b5 2d 5f a0 05 ab  f1 93 58 75 4a 87 35     |...-_.....XuJ.5|
+00000000  17 03 01 00 20 e0 71 e9  54 11 6e 48 4b be a2 2a  |.... .q.T.nHK..*|
+00000010  b1 70 d2 2c 74 c0 f4 74  05 f1 d3 d6 84 29 58 f7  |.p.,t..t.....)X.|
+00000020  87 90 84 2b c8 17 03 01  00 20 b6 a2 e9 e0 f0 0d  |...+..... ......|
+00000030  d5 ef d7 32 6d cb 99 5d  a6 37 c2 6e f9 c3 8e 6f  |...2m..].7.n...o|
+00000040  76 71 d8 a6 c5 ae 4e 04  77 06 15 03 01 00 20 f2  |vq....N.w..... .|
+00000050  09 ab dc 37 90 78 3a 2a  41 ab 9b a9 c1 78 2a 64  |...7.x:*A....x*d|
+00000060  a8 3f 21 c4 bb af 76 b3  c6 2f e1 20 a3 b1 1e     |.?!...v../. ...|
index 9b1a5533acf093c6147fb7ff08a8432e62d3e5a0..e00787037ab2212fda06695165fbcbd87f145632 100644 (file)
@@ -1,65 +1,60 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 51 02 00 00  4d 03 01 90 e6 e1 c6 bd  |....Q...M.......|
-00000010  86 08 db 33 94 f3 bd 0b  2d fc e0 ba 89 a7 c5 66  |...3....-......f|
-00000020  a5 19 78 33 2b b9 c4 22  d8 e0 63 20 2e 85 53 25  |..x3+.."..c ..S%|
-00000030  f2 22 e3 ca 79 94 9e 50  00 13 da 9d 21 33 49 27  |."..y..P....!3I'|
-00000040  9b 44 c5 10 bc e8 44 01  04 31 02 81 00 05 00 00  |.D....D..1......|
-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..|
-00000080  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000090  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-000000a0  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-000000b0  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000c0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000d0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000e0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000f0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-00000100  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-00000110  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000120  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000130  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000140  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000150  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000160  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000170  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000180  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000190  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-000001a0  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-000001b0  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001c0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001d0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001e0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001f0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-00000200  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-00000210  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000220  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000230  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000240  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000250  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000260  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000270  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000280  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000290  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-000002a0  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-000002b0  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002c0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002d0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002e0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002f0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-00000300  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 01 00 0e 0d 00  |n8P)l...........|
-00000320  00 06 03 01 02 40 00 00  0e 00 00 00              |.....@......|
+00000000  16 03 01 00 51 02 00 00  4d 03 01 e5 d7 4b 56 7b  |....Q...M....KV{|
+00000010  a8 2c 07 33 fc 66 d7 79  e9 26 91 56 7d 9d 99 1d  |.,.3.f.y.&.V}...|
+00000020  b2 24 36 2c f6 78 3a e7  63 15 f6 20 9f e1 d4 07  |.$6,.x:.c.. ....|
+00000030  a9 75 3d b9 3b 8c 46 cb  a7 37 36 56 af 4e 99 cf  |.u=.;.F..76V.N..|
+00000040  90 49 e1 e9 69 25 81 0f  fd 22 48 e6 00 05 00 00  |.I..i%..."H.....|
+00000050  05 ff 01 00 01 00 16 03  01 02 71 0b 00 02 6d 00  |..........q...m.|
+00000060  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000070  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000080  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000090  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+000000a0  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+000000b0  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000c0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000d0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000e0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000f0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+00000100  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+00000110  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000120  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000130  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000140  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000150  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000160  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000170  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000180  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000190  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+000001a0  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+000001b0  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001c0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001d0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001e0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001f0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+00000200  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+00000210  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f..@....xH.A0.|
+00000220  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000230  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000240  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000250  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H@.-.....|
+00000260  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000270  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000280  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000290  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+000002a0  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+000002b0  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002c0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 01 00  |..A4......9.....|
+000002d0  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|
 000001d0  8b ec ab 67 be c8 64 b0  11 50 46 58 17 6b 99 1c  |...g..d..PFX.k..|
 000001e0  d3 1d fc 06 f1 0e e5 96  a8 0c f9 78 20 b7 44 18  |...........x .D.|
 000001f0  51 8d 10 7e 4f 94 67 df  a3 4e 70 73 8e 90 91 85  |Q..~O.g..Nps....|
-00000200  16 03 01 00 86 10 00 00  82 00 80 6d 51 f3 7f f9  |...........mQ...|
-00000210  3e fb 75 82 41 36 83 e8  6a ee 2a 2e 25 90 67 4c  |>.u.A6..j.*.%.gL|
-00000220  8e 62 2f 30 81 17 e0 85  09 0c 2b b7 23 d7 b0 e2  |.b/0......+.#...|
-00000230  1d f7 3b d7 f5 a1 27 b6  ee 24 b6 1b cc 5b ea 66  |..;...'..$...[.f|
-00000240  0d 6a f4 e5 85 f9 da 43  b4 0e 86 85 e1 f5 aa be  |.j.....C........|
-00000250  c8 ce 39 4c 9c 86 00 08  c2 4b e2 c6 ec 2f f7 ce  |..9L.....K.../..|
-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 10 19  57 14 c3 ee 2d da cb de  |........W...-...|
-000002a0  f3 70 c5 62 91 2f ad 62  dd 10 f1 65 20 a2 cf d5  |.p.b./.b...e ...|
-000002b0  cd 6d 5f e4 b3 3e 38 e8  d0 1a f7 f0 e7 7e b6 5d  |.m_..>8......~.]|
-000002c0  c3 6c ad f6 0d 05 1e 41  35 2d 04 15 3c 36 96 00  |.l.....A5-..<6..|
-000002d0  e8 02 b2 01 b8 9f 21 4b  34 85 ef 5e 4c 87 ef 49  |......!K4..^L..I|
-000002e0  df d1 9a b6 b2 bd b8 90  fd 3f 31 93 0c dc c7 18  |.........?1.....|
-000002f0  ff f6 76 bd 5b 74 76 b3  62 87 6a df ff 63 15 d5  |..v.[tv.b.j..c..|
-00000300  94 d5 fe fd 4c 12 df f1  35 07 f1 8a f1 77 7a 35  |....L...5....wz5|
-00000310  cd 99 1d 2a d7 9a 14 03  01 00 01 01 16 03 01 00  |...*............|
-00000320  24 8d db 0c 87 b5 df fd  68 de fe 46 3e e4 41 b5  |$.......h..F>.A.|
-00000330  19 64 68 3c c4 e2 2b 43  50 e4 ee 52 75 34 d3 c1  |.dh<..+CP..Ru4..|
-00000340  51 18 c0 b2 5f                                    |Q..._|
+00000200  16 03 01 00 86 10 00 00  82 00 80 73 bd 73 65 92  |...........s.se.|
+00000210  86 23 41 14 79 7f d5 c1  10 ce 94 4d ad 9c c3 a9  |.#A.y......M....|
+00000220  87 b5 32 52 f8 6b 11 93  2d 9b 98 0b 8b 1d c0 f6  |..2R.k..-.......|
+00000230  53 17 6d c7 9c 2e ae c9  6f cc 99 23 38 37 1a 10  |S.m.....o..#87..|
+00000240  fe 05 0b b5 55 0a 14 e9  60 7d 70 26 98 e2 54 d9  |....U...`}p&..T.|
+00000250  65 cf 2e f4 53 5f 1d aa  3a f6 33 7b eb 4c 0e b3  |e...S_..:.3{.L..|
+00000260  ff 5a db 36 2a 47 f3 df  f9 fc f5 31 78 83 aa 6b  |.Z.6*G.....1x..k|
+00000270  52 b7 ba 1a 96 bc fa c1  a1 a9 bb 2b f5 38 89 00  |R..........+.8..|
+00000280  4d e5 78 13 4e a4 38 46  42 dc 16 16 03 01 00 86  |M.x.N.8FB.......|
+00000290  0f 00 00 82 00 80 3d f7  ff c1 72 82 b8 90 42 a3  |......=...r...B.|
+000002a0  10 24 b5 01 44 60 98 39  e4 36 86 56 09 55 e5 73  |.$..D`.9.6.V.U.s|
+000002b0  3a d9 9d 00 ae 05 23 6f  78 4e 49 28 c1 cc 7a ff  |:.....#oxNI(..z.|
+000002c0  8f 67 92 cd 94 c0 d2 68  7f 48 ec 10 83 48 9e 02  |.g.....h.H...H..|
+000002d0  b8 10 b2 1b f0 ba 8f 5a  c8 85 d9 19 53 c2 8d 37  |.......Z....S..7|
+000002e0  8e 86 4c ca ee 0f c4 97  20 f9 a5 4e 94 b8 c5 c5  |..L..... ..N....|
+000002f0  53 0c c1 b6 e5 a1 4e d6  15 b3 6b 08 c2 25 c3 de  |S.....N...k..%..|
+00000300  e7 69 85 85 56 31 16 ad  68 7e 00 8f 1b fc f8 9f  |.i..V1..h~......|
+00000310  d7 50 87 08 0d c5 14 03  01 00 01 01 16 03 01 00  |.P..............|
+00000320  24 eb 0c f3 4f 56 04 e3  54 b0 a8 e4 bb af 3a 44  |$...OV..T.....:D|
+00000330  c7 d6 f0 24 2f fc e6 79  93 f4 4e ec c5 1f 5b 99  |...$/..y..N...[.|
+00000340  32 37 c2 f1 ad                                    |27...|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 24 0b a4 04 46 60  |..........$...F`|
-00000010  15 fb 9a 9f 47 51 6d b4  4b c6 e7 2a 1b 98 b4 8a  |....GQm.K..*....|
-00000020  8a 1a 03 cf f4 16 7d 80  70 27 e5 e8 d5 9f ad     |......}.p'.....|
+00000000  14 03 01 00 01 01 16 03  01 00 24 75 ac 09 a6 28  |..........$u...(|
+00000010  60 ce 7f 81 a2 75 86 af  84 95 dc 3f e1 07 1c 02  |`....u.....?....|
+00000020  bc 3c 90 db 1e 1a 35 06  93 60 22 69 b9 05 bb     |.<....5..`"i...|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 1a 6f 84 50  27 c7 f1 aa b0 04 7d 80  |.....o.P'.....}.|
-00000010  6d a7 20 8a 73 cf d9 de  9a d6 f5 e9 36 13 7c 15  |m. .s.......6.|.|
-00000020  03 01 00 16 e8 0b e0 a6  3b 1e 21 24 65 4e 49 b2  |........;.!$eNI.|
-00000030  2d a3 41 2b 98 23 4e d5  4b fd                    |-.A+.#N.K.|
+00000000  17 03 01 00 1a f4 67 a7  d8 0a 67 8d 3a 11 53 7e  |......g...g.:.S~|
+00000010  49 91 bf 92 85 e0 35 24  25 72 92 26 63 9b 09 15  |I.....5$%r.&c...|
+00000020  03 01 00 16 98 bb a0 ca  40 70 26 6f 2d 73 35 3d  |........@p&o-s5=|
+00000030  90 8c ff 01 e0 b1 50 52  e3 57                    |......PR.W|
index 937c2909f904ab50f75b26fd24ec37905db769fe..929e1c6b12babfa8784465250197af6c0a45d857 100644 (file)
@@ -1,19 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 59 02 00 00  55 03 01 f5 8f 8d 8e ca  |....Y...U.......|
-00000010  30 6b fe 63 c9 84 57 c0  f1 c8 a5 d8 10 56 14 62  |0k.c..W......V.b|
-00000020  c8 02 b2 89 21 5c 09 67  86 d8 9b 20 dc 3f 55 54  |....!\.g... .?UT|
-00000030  33 29 47 45 d3 e0 87 1a  4b 1b 75 30 89 e0 4d 01  |3)GE....K.u0..M.|
-00000040  a1 6a 46 f7 8f 23 d6 74  fd 90 2f 53 c0 09 00 00  |.jF..#.t../S....|
+00000000  16 03 01 00 59 02 00 00  55 03 01 78 09 57 86 09  |....Y...U..x.W..|
+00000010  64 7e 35 c7 c7 b9 44 9c  09 ae f0 49 cb 1c 1f 58  |d~5...D....I...X|
+00000020  89 ef 65 16 9e 32 73 cd  4d 1b 8f 20 10 4d 5b cf  |..e..2s.M.. .M[.|
+00000030  d0 24 59 dd e8 47 c9 a2  ad 9c 98 b5 eb 16 46 6b  |.$Y..G........Fk|
+00000040  7d 33 6e 53 0a 3d 81 71  a1 bc 43 7a c0 09 00 00  |}3nS.=.q..Cz....|
 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....|
 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 22  |*............A."|
-00000280  8a 47 c6 d3 7a c4 30 a4  8e 41 11 ac b3 2d 2f 45  |.G..z.0..A...-/E|
-00000290  61 54 9b 1f 2e 03 5d 50  eb fc 5b 44 a0 a7 48 78  |aT....]P..[D..Hx|
-000002a0  ce 14 d5 39 a7 c4 ed f5  4d 8f da 9d 71 52 69 70  |...9....M...qRip|
-000002b0  7e 52 29 ad 80 8a 19 ad  4c 5d 1c f1 22 7e 1a 00  |~R).....L].."~..|
-000002c0  8a 30 81 87 02 42 00 97  8b 6d f7 87 c1 a9 a6 55  |.0...B...m.....U|
-000002d0  0f 61 c2 f2 e1 05 26 a8  83 16 1c 0b 69 3b 95 57  |.a....&.....i;.W|
-000002e0  76 5b eb 45 7a bd 6a f1  3e a0 93 49 fa 74 32 fd  |v[.Ez.j.>..I.t2.|
-000002f0  dc 20 3a bb e3 ee 6d b8  56 aa e9 d2 7d 6a ec b7  |. :...m.V...}j..|
-00000300  0a bd aa dc d7 b0 69 65  02 41 4d 19 61 16 d8 5f  |......ie.AM.a.._|
-00000310  1d c1 32 25 15 26 eb 88  5b c1 dd 9a 12 40 fa f1  |..2%.&..[....@..|
-00000320  81 5e 7d b8 2b 6e 60 63  1a 9e 86 cb d5 64 96 d4  |.^}.+n`c.....d..|
-00000330  75 fc 02 33 e0 66 60 b2  40 47 cf e6 6d 25 9c 83  |u..3.f`.@G..m%..|
-00000340  23 d3 4b e2 eb ac f1 56  44 f8 3f 16 03 01 00 04  |#.K....VD.?.....|
-00000350  0e 00 00 00                                       |....|
+00000270  2a 16 03 01 00 d6 0c 00  00 d2 03 00 17 41 04 51  |*............A.Q|
+00000280  39 70 43 9c 01 de 29 df  3c d0 f8 31 54 70 34 53  |9pC...).<..1Tp4S|
+00000290  0e ab e8 e0 b0 8b 21 66  63 ac a9 68 7c 92 6f f8  |......!fc..h|.o.|
+000002a0  cf a3 ba cb 6d 39 f4 5c  f5 2e ff 1d d7 1b b9 e7  |....m9.\........|
+000002b0  08 13 59 f8 64 7e 23 e0  1d 04 cf 37 47 d6 b7 00  |..Y.d~#....7G...|
+000002c0  8b 30 81 88 02 42 01 cd  1d 01 46 68 da 4c b6 0d  |.0...B....Fh.L..|
+000002d0  67 05 39 0d aa 6c c5 40  e4 5d bf 4f 2a 92 78 8d  |g.9..l.@.].O*.x.|
+000002e0  08 0e c0 07 8c 68 cc 55  4e 54 a9 9d 22 f9 a6 4a  |.....h.UNT.."..J|
+000002f0  e4 38 9f 53 4a 60 e8 eb  81 02 50 75 7e 13 31 2a  |.8.SJ`....Pu~.1*|
+00000300  ff 3e 17 cd b4 d1 d4 75  02 42 01 95 ba b6 a0 12  |.>.....u.B......|
+00000310  23 59 9f ae 1c c0 60 d2  8f 59 6b 35 ee b3 3f ac  |#Y....`..Yk5..?.|
+00000320  e4 42 9a 23 d0 f4 fd a1  3c 36 1b 31 33 76 8d f0  |.B.#....<6.13v..|
+00000330  b6 66 fd 92 9a 2a 27 8b  06 11 72 41 09 bd 27 55  |.f...*'...rA..'U|
+00000340  c7 1b a9 d1 49 5e 8f 85  dc aa 9d be 16 03 01 00  |....I^..........|
+00000350  04 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..|
 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 cc 86  f1 7e 6e a8 c9 b5 02 5f  |.....0...~n...._|
-00000060  fb b2 3b ea 74 bf a8 da  e4 6a 69 50 a2 5a 78 4f  |..;.t....jiP.ZxO|
-00000070  35 e1 cc 87 c3 fb 1f 5e  f6 a4 5c 63 cc 59 12 3e  |5......^..\c.Y.>|
-00000080  07 c3 a8 d7 87 ba                                 |......|
+00000050  01 16 03 01 00 30 64 61  7f ea 98 8e e7 c9 0f ea  |.....0da........|
+00000060  0a b3 52 ba 3d 01 36 a4  47 24 7b 2d 19 b5 7e 92  |..R.=.6.G${-..~.|
+00000070  04 b7 8c 4f fc 02 5d 79  15 3e 50 72 05 3c df d2  |...O..]y.>Pr.<..|
+00000080  c6 a3 b3 c8 7c 48                                 |....|H|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 e8 b6 20 b9 c1  |..........0.. ..|
-00000010  07 38 38 bb 42 b2 b2 a1  c5 8d 92 62 db 67 ab fc  |.88.B......b.g..|
-00000020  f6 64 3f 71 83 1d a0 86  bb 2d e3 4f 65 d5 44 52  |.d?q.....-.Oe.DR|
-00000030  4d f5 62 80 3c af 95 87  19 7c 20                 |M.b.<....| |
+00000000  14 03 01 00 01 01 16 03  01 00 30 7d 49 8d e9 da  |..........0}I...|
+00000010  87 77 18 4d 10 63 17 ed  1f 34 7a d4 be e3 dd b6  |.w.M.c...4z.....|
+00000020  8b f3 a7 06 bc de 76 8e  04 be 8a 95 5b 24 19 ec  |......v.....[$..|
+00000030  66 55 8a 1b e0 df 0b a1  57 cb 67                 |fU......W.g|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 20 bd 65 61  28 e5 ea 1b 81 db 75 92  |.... .ea(.....u.|
-00000010  ad a7 3b 01 a3 23 0e 3b  60 10 8a 1e 04 91 fb 9e  |..;..#.;`.......|
-00000020  7a cf 1f cf 9c 17 03 01  00 20 87 9c dc ed 0d 08  |z........ ......|
-00000030  56 40 23 8b c5 2c d8 7e  42 82 3c 0a c9 f3 77 6d  |V@#..,.~B.<...wm|
-00000040  8d 9a 30 d1 9c c4 ae 04  fb b7 15 03 01 00 20 f7  |..0........... .|
-00000050  f0 12 0d e5 03 c1 80 4e  7e 21 d7 75 55 1c 91 89  |.......N~!.uU...|
-00000060  e7 e1 45 fc 7d d8 fc b1  d0 e7 dc e2 4c ba f4     |..E.}.......L..|
+00000000  17 03 01 00 20 2d a3 e5  55 13 3f 73 8e ba 41 79  |.... -..U.?s..Ay|
+00000010  65 e0 83 d5 3a ea cd e9  a8 b4 4b 3c d0 0c bf 06  |e...:.....K<....|
+00000020  75 2a 67 f2 f7 17 03 01  00 20 a0 8d 3c a2 ca b3  |u*g...... ..<...|
+00000030  f3 e5 36 dc 44 a4 3b ad  cd 03 be a9 70 a8 75 51  |..6.D.;.....p.uQ|
+00000040  0f 8e 9f 7c a7 3c 03 84  38 88 15 03 01 00 20 75  |...|.<..8..... u|
+00000050  0f db fe 48 b4 7e 04 3b  f5 5b 47 5b 0a ab 69 18  |...H.~.;.[G[..i.|
+00000060  37 bb 89 d3 a8 40 ba 53  3b 5f 6d 8b 06 ff ae     |7....@.S;_m....|
index f8183f103539129755173db2aaa0eb1e4869bb62..0b481ea5ecb0b11d3c6beed01c8b35fc3dea296c 100644 (file)
@@ -1,98 +1,93 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 59 02 00 00  55 03 01 5c 69 d0 60 d6  |....Y...U..\i.`.|
-00000010  b3 f4 23 19 5e 3e 26 d8  29 ea c3 94 e4 ed 51 f6  |..#.^>&.).....Q.|
-00000020  58 a2 e3 9c 79 a1 0b 6d  29 90 32 20 23 5b 47 b1  |X...y..m).2 #[G.|
-00000030  8f 22 bc 06 aa ee f7 c3  97 ca 93 df b1 90 7d b4  |."............}.|
-00000040  8c c0 d9 54 35 ca 5b 11  98 37 84 ea c0 13 00 00  |...T5.[..7......|
+00000000  16 03 01 00 59 02 00 00  55 03 01 90 3d f6 98 16  |....Y...U...=...|
+00000010  55 0f 73 94 05 96 4c ab  ad f4 98 7a db c5 ca 26  |U.s...L....z...&|
+00000020  1b c8 d9 15 a8 79 8e 2b  10 67 54 20 b2 8e 45 24  |.....y.+.gT ..E$|
+00000030  6d 82 ec f5 30 41 2e 32  10 fa c0 76 3f 84 81 39  |m...0A.2...v?..9|
+00000040  1e 5d 98 c1 33 d9 0d 4f  21 e1 0d 47 c0 13 00 00  |.]..3..O!..G....|
 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..............|
-00000080  a4 8a 7f b8 ca 30 0d 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
-00000090  01 05 05 00 30 45 31 0b  30 09 06 03 55 04 06 13  |....0E1.0...U...|
-000000a0  02 41 55 31 13 30 11 06  03 55 04 08 13 0a 53 6f  |.AU1.0...U....So|
-000000b0  6d 65 2d 53 74 61 74 65  31 21 30 1f 06 03 55 04  |me-State1!0...U.|
-000000c0  0a 13 18 49 6e 74 65 72  6e 65 74 20 57 69 64 67  |...Internet Widg|
-000000d0  69 74 73 20 50 74 79 20  4c 74 64 30 1e 17 0d 31  |its Pty Ltd0...1|
-000000e0  30 30 34 32 34 30 39 30  39 33 38 5a 17 0d 31 31  |00424090938Z..11|
-000000f0  30 34 32 34 30 39 30 39  33 38 5a 30 45 31 0b 30  |0424090938Z0E1.0|
-00000100  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
-00000110  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
-00000120  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
-00000130  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
-00000140  74 64 30 81 9f 30 0d 06  09 2a 86 48 86 f7 0d 01  |td0..0...*.H....|
-00000150  01 01 05 00 03 81 8d 00  30 81 89 02 81 81 00 bb  |........0.......|
-00000160  79 d6 f5 17 b5 e5 bf 46  10 d0 dc 69 be e6 2b 07  |y......F...i..+.|
-00000170  43 5a d0 03 2d 8a 7a 43  85 b7 14 52 e7 a5 65 4c  |CZ..-.zC...R..eL|
-00000180  2c 78 b8 23 8c b5 b4 82  e5 de 1f 95 3b 7e 62 a5  |,x.#........;~b.|
-00000190  2c a5 33 d6 fe 12 5c 7a  56 fc f5 06 bf fa 58 7b  |,.3...\zV.....X{|
-000001a0  26 3f b5 cd 04 d3 d0 c9  21 96 4a c7 f4 54 9f 5a  |&?......!.J..T.Z|
-000001b0  bf ef 42 71 00 fe 18 99  07 7f 7e 88 7d 7d f1 04  |..Bq......~.}}..|
-000001c0  39 c4 a2 2e db 51 c9 7c  e3 c0 4c 3b 32 66 01 cf  |9....Q.|..L;2f..|
-000001d0  af b1 1d b8 71 9a 1d db  db 89 6b ae da 2d 79 02  |....q.....k..-y.|
-000001e0  03 01 00 01 a3 81 a7 30  81 a4 30 1d 06 03 55 1d  |.......0..0...U.|
-000001f0  0e 04 16 04 14 b1 ad e2  85 5a cf cb 28 db 69 ce  |.........Z..(.i.|
-00000200  23 69 de d3 26 8e 18 88  39 30 75 06 03 55 1d 23  |#i..&...90u..U.#|
-00000210  04 6e 30 6c 80 14 b1 ad  e2 85 5a cf cb 28 db 69  |.n0l......Z..(.i|
-00000220  ce 23 69 de d3 26 8e 18  88 39 a1 49 a4 47 30 45  |.#i..&...9.I.G0E|
-00000230  31 0b 30 09 06 03 55 04  06 13 02 41 55 31 13 30  |1.0...U....AU1.0|
-00000240  11 06 03 55 04 08 13 0a  53 6f 6d 65 2d 53 74 61  |...U....Some-Sta|
-00000250  74 65 31 21 30 1f 06 03  55 04 0a 13 18 49 6e 74  |te1!0...U....Int|
-00000260  65 72 6e 65 74 20 57 69  64 67 69 74 73 20 50 74  |ernet Widgits Pt|
-00000270  79 20 4c 74 64 82 09 00  85 b0 bb a4 8a 7f b8 ca  |y Ltd...........|
-00000280  30 0c 06 03 55 1d 13 04  05 30 03 01 01 ff 30 0d  |0...U....0....0.|
-00000290  06 09 2a 86 48 86 f7 0d  01 01 05 05 00 03 81 81  |..*.H...........|
-000002a0  00 08 6c 45 24 c7 6b b1  59 ab 0c 52 cc f2 b0 14  |..lE$.k.Y..R....|
-000002b0  d7 87 9d 7a 64 75 b5 5a  95 66 e4 c5 2b 8e ae 12  |...zdu.Z.f..+...|
-000002c0  66 1f eb 4f 38 b3 6e 60  d3 92 fd f7 41 08 b5 25  |f..O8.n`....A..%|
-000002d0  13 b1 18 7a 24 fb 30 1d  ba ed 98 b9 17 ec e7 d7  |...z$.0.........|
-000002e0  31 59 db 95 d3 1d 78 ea  50 56 5c d5 82 5a 2d 5a  |1Y....x.PV\..Z-Z|
-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 a6  |.............A..|
-00000330  57 60 8d 63 4e 4d 3f 48  e0 5d ad 9a 9c f7 e6 8c  |W`.cNM?H.]......|
-00000340  00 18 9c eb 34 ea f0 5c  d5 77 3f af 81 a9 50 d9  |....4..\.w?...P.|
-00000350  05 cf b9 bf 88 5c 70 29  24 61 6f d8 77 11 21 57  |.....\p)$ao.w.!W|
-00000360  a0 4d e1 4b 8e 55 06 50  7f a2 30 c1 c2 b9 c6 00  |.M.K.U.P..0.....|
-00000370  80 68 7c e4 1a bc a4 1e  16 b9 3e 4a 59 39 a9 54  |.h|.......>JY9.T|
-00000380  6f c7 17 b2 f5 af b5 73  5b db cc 71 f2 1b aa dc  |o......s[..q....|
-00000390  9d 64 3c 0f 82 e6 da 1a  6b 96 19 e2 f0 15 b0 df  |.d<.....k.......|
-000003a0  8a 2d 96 09 63 52 f6 53  ef 12 d4 3b 35 b7 0b 43  |.-..cR.S...;5..C|
-000003b0  2c 6e 58 4c c8 2f b8 55  84 89 c9 39 81 7a 7a 7d  |,nXL./.U...9.zz}|
-000003c0  88 68 db eb d7 81 aa 2e  b2 25 ba 98 6c 46 b7 85  |.h.......%..lF..|
-000003d0  8a 21 17 b9 36 23 c0 84  94 af 3b 9b 04 5d ec 31  |.!..6#....;..].1|
-000003e0  f5 75 84 d8 77 d7 80 37  ae c3 5c 26 41 f6 72 af  |.u..w..7..\&A.r.|
-000003f0  88 16 03 01 00 04 0e 00  00 00                    |..........|
+00000060  01 02 71 0b 00 02 6d 00  02 6a 00 02 67 30 82 02  |..q...m..j..g0..|
+00000070  63 30 82 01 cc a0 03 02  01 02 02 09 00 a2 73 00  |c0............s.|
+00000080  0c 81 00 cb f3 30 0d 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
+00000090  01 0b 05 00 30 2b 31 17  30 15 06 03 55 04 0a 13  |....0+1.0...U...|
+000000a0  0e 47 6f 6f 67 6c 65 20  54 45 53 54 49 4e 47 31  |.Google TESTING1|
+000000b0  10 30 0e 06 03 55 04 03  13 07 47 6f 20 52 6f 6f  |.0...U....Go Roo|
+000000c0  74 30 1e 17 0d 31 35 30  31 30 31 30 30 30 30 30  |t0...15010100000|
+000000d0  30 5a 17 0d 32 35 30 31  30 31 30 30 30 30 30 30  |0Z..250101000000|
+000000e0  5a 30 26 31 17 30 15 06  03 55 04 0a 13 0e 47 6f  |Z0&1.0...U....Go|
+000000f0  6f 67 6c 65 20 54 45 53  54 49 4e 47 31 0b 30 09  |ogle TESTING1.0.|
+00000100  06 03 55 04 03 13 02 47  6f 30 81 9f 30 0d 06 09  |..U....Go0..0...|
+00000110  2a 86 48 86 f7 0d 01 01  01 05 00 03 81 8d 00 30  |*.H............0|
+00000120  81 89 02 81 81 00 af 87  88 f6 20 1b 95 65 6c 14  |.......... ..el.|
+00000130  ab 44 05 af 3b 45 14 e3  b7 6d fd 00 63 4d 95 7f  |.D..;E...m..cM..|
+00000140  fe 6a 62 35 86 c0 4a f9  18 7c f6 aa 25 5e 7a 64  |.jb5..J..|..%^zd|
+00000150  31 66 00 ba f4 8e 92 af  c7 6b d8 76 d4 f3 5f 41  |1f.......k.v.._A|
+00000160  cb 6e 56 15 97 1b 97 c1  3c 12 39 21 66 3d 2b 16  |.nV.....<.9!f=+.|
+00000170  d1 bc db 1c c0 a7 da b7  ca ad ba da cb d5 21 50  |..............!P|
+00000180  ec de 8d ab d1 6b 81 4b  89 02 f3 c4 be c1 6c 89  |.....k.K......l.|
+00000190  b1 44 84 bd 21 d1 04 7d  9d 16 4d f9 82 15 f6 ef  |.D..!..}..M.....|
+000001a0  fa d6 09 47 f2 fb 02 03  01 00 01 a3 81 93 30 81  |...G..........0.|
+000001b0  90 30 0e 06 03 55 1d 0f  01 01 ff 04 04 03 02 05  |.0...U..........|
+000001c0  a0 30 1d 06 03 55 1d 25  04 16 30 14 06 08 2b 06  |.0...U.%..0...+.|
+000001d0  01 05 05 07 03 01 06 08  2b 06 01 05 05 07 03 02  |........+.......|
+000001e0  30 0c 06 03 55 1d 13 01  01 ff 04 02 30 00 30 19  |0...U.......0.0.|
+000001f0  06 03 55 1d 0e 04 12 04  10 12 50 8d 89 6f 1b d1  |..U.......P..o..|
+00000200  dc 54 4d 6e cb 69 5e 06  f4 30 1b 06 03 55 1d 23  |.TMn.i^..0...U.#|
+00000210  04 14 30 12 80 10 bf 3d  b6 a9 66 f2 b8 40 cf ea  |..0....=..f..@..|
+00000220  b4 03 78 48 1a 41 30 19  06 03 55 1d 11 04 12 30  |..xH.A0...U....0|
+00000230  10 82 0e 65 78 61 6d 70  6c 65 2e 67 6f 6c 61 6e  |...example.golan|
+00000240  67 30 0d 06 09 2a 86 48  86 f7 0d 01 01 0b 05 00  |g0...*.H........|
+00000250  03 81 81 00 92 7c af 91  55 12 18 96 59 31 a6 48  |.....|..U...Y1.H|
+00000260  40 d5 2d d5 ee bb 02 a0  f5 c2 1e 7c 9b b3 30 7d  |@.-........|..0}|
+00000270  3c dc 76 da 4f 3d c0 fa  ae 2d 33 24 6b 03 7b 1b  |<.v.O=...-3$k.{.|
+00000280  67 59 11 21 b5 11 bc 77  b9 d9 e0 6e a8 2d 2e 35  |gY.!...w...n.-.5|
+00000290  fa 64 5f 22 3e 63 10 6b  be ff 14 86 6d 0d f0 15  |.d_">c.k....m...|
+000002a0  31 a8 14 38 1e 3b 84 87  2c cb 98 ed 51 76 b9 b1  |1..8.;..,...Qv..|
+000002b0  4f dd db 9b 84 04 86 40  fa 51 dd ba b4 8d eb e3  |O......@.Q......|
+000002c0  46 de 46 b9 4f 86 c7 f9  a4 c2 41 34 ac cc f6 ea  |F.F.O.....A4....|
+000002d0  b0 ab 39 18 16 03 01 00  cb 0c 00 00 c7 03 00 17  |..9.............|
+000002e0  41 04 d9 ae 3f 05 64 d3  77 d9 1d b8 37 8a d4 ac  |A...?.d.w...7...|
+000002f0  51 f4 af 65 70 da c0 64  76 00 53 50 a2 d4 6c bc  |Q..ep..dv.SP..l.|
+00000300  9c 62 ab 2f 7b 02 48 fe  b2 0d 0b bb be 8f 34 55  |.b./{.H.......4U|
+00000310  fb ce ee 93 43 76 d5 ce  3b b5 79 ab 3d 74 6e 19  |....Cv..;.y.=tn.|
+00000320  a9 7d 00 80 05 cf 57 f2  f7 e0 ad 71 f1 75 d0 8b  |.}....W....q.u..|
+00000330  f5 9d 83 1a 7e 0a 71 10  d7 9e fe bd 9d 47 62 45  |....~.q......GbE|
+00000340  8d 1b 9c 33 fa 2c 5c aa  ce 9e 62 dc ad 56 ac 87  |...3.,\...b..V..|
+00000350  84 54 f5 32 87 d1 bb 8b  d9 d7 6d 3c 6c 6d b7 79  |.T.2......m<lm.y|
+00000360  05 4d 55 f1 7c ef b1 fc  e7 35 5d 41 66 60 44 4f  |.MU.|....5]Af`DO|
+00000370  f3 dd de 25 f4 73 12 c2  b6 cc 61 d5 14 5a ff 88  |...%.s....a..Z..|
+00000380  ae f5 04 62 ac 2d 10 a0  95 c1 8e fa e6 db fe 41  |...b.-.........A|
+00000390  46 98 f1 3d 2e e3 2a 5a  ea 87 26 6e 7a 4f 38 6c  |F..=..*Z..&nzO8l|
+000003a0  4b 1f 1b 56 16 03 01 00  04 0e 00 00 00           |K..V.........|
 >>> 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 d2 5b  27 5a f5 64 49 31 d5 aa  |.....0.['Z.dI1..|
-00000060  a3 72 ae c9 af 0b aa 75  af ac f3 45 f4 e3 03 fa  |.r.....u...E....|
-00000070  e8 97 88 7b 51 a9 ae 61  40 c8 11 74 3e d8 9a b6  |...{Q..a@..t>...|
-00000080  e7 6a 5e 71 84 7e                                 |.j^q.~|
+00000050  01 16 03 01 00 30 73 96  2d 54 e3 9a bc 54 f5 9e  |.....0s.-T...T..|
+00000060  e5 c7 46 35 b8 e1 d6 f6  14 95 92 f1 95 81 5a 9d  |..F5..........Z.|
+00000070  4b df cc 96 77 f2 39 60  5d 5d da 94 b0 bf a0 80  |K...w.9`]]......|
+00000080  bd 28 55 b1 6a c3                                 |.(U.j.|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 8d 63 fc 58 2e  |..........0.c.X.|
-00000010  50 f7 60 2c 9f 5a 8e 58  29 6c a6 3a 8d 2b a7 2b  |P.`,.Z.X)l.:.+.+|
-00000020  1c 12 8a 53 3f d5 60 79  12 c3 78 e3 aa 50 15 45  |...S?.`y..x..P.E|
-00000030  07 da 2d c7 a9 c3 45 07  48 00 78                 |..-...E.H.x|
+00000000  14 03 01 00 01 01 16 03  01 00 30 c9 46 7a 8b be  |..........0.Fz..|
+00000010  cd eb 5c 83 13 9c 9b 9f  70 84 38 3b 48 8c f4 11  |..\.....p.8;H...|
+00000020  b3 ca 10 09 38 d0 8e c8  9f 66 db b9 8a 95 15 6b  |....8....f.....k|
+00000030  5e f8 1d 39 25 75 3d f1  b9 32 a3                 |^..9%u=..2.|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 20 40 91 8d  e6 95 2f 97 c8 0c 94 5c  |.... @..../....\|
-00000010  46 a7 d3 31 82 3d dc 7e  86 5b dd df 3f 3b 5b 9c  |F..1.=.~.[..?;[.|
-00000020  d5 0d 52 5a 53 17 03 01  00 20 1d 18 da 6b e8 66  |..RZS.... ...k.f|
-00000030  ce 58 18 81 4b 69 8c f6  db 1a ee d0 78 fb f5 68  |.X..Ki......x..h|
-00000040  2c 99 48 47 65 15 2a ae  ff 4e 15 03 01 00 20 68  |,.HGe.*..N.... h|
-00000050  aa 7f 75 33 45 7a 1a 33  18 35 5a 5b 14 b0 f6 83  |..u3Ez.3.5Z[....|
-00000060  97 85 3f b2 dc 78 68 eb  43 ef 92 7f 38 bd f8     |..?..xh.C...8..|
+00000000  17 03 01 00 20 04 69 a9  01 42 f4 1a fd 5a 4e 12  |.... .i..B...ZN.|
+00000010  2b 6d cd 68 6b 94 70 b2  80 07 cf 79 a4 43 69 bf  |+m.hk.p....y.Ci.|
+00000020  27 25 b5 ae e7 17 03 01  00 20 bf 1e cd 83 64 af  |'%....... ....d.|
+00000030  6f cc 89 21 bf 16 e7 e8  86 29 f3 0a 36 ab a4 e3  |o..!.....)..6...|
+00000040  fa c0 7e 7a 78 ca 29 17  11 9c 15 03 01 00 20 94  |..~zx.)....... .|
+00000050  7a dd 17 eb fd 67 b1 cc  58 c9 c3 ae db b6 b0 a4  |z....g..X.......|
+00000060  68 15 36 ca 33 22 ec 03  fb cf 2f f5 70 d6 9d     |h.6.3"..../.p..|
index b5deaeb011a460f331fbfbb18430174577977a24..57eb930d092d091c5e23a39608e4e877dbfd811f 100644 (file)
@@ -1,84 +1,79 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 51 02 00 00  4d 03 01 a9 b0 bf 24 3f  |....Q...M.....$?|
-00000010  98 c6 0f 83 23 2b b6 e4  3f d5 5b 10 9a 6f b8 63  |....#+..?.[..o.c|
-00000020  4c 3c d6 4d 05 c0 08 85  f7 72 72 20 ab 85 8c ff  |L<.M.....rr ....|
-00000030  f7 bb 95 ab 69 37 3d b6  79 cb 46 ad 4e 22 e7 c6  |....i7=.y.F.N"..|
-00000040  a5 9b 72 92 32 ff a5 f7  ed dc 30 41 00 05 00 00  |..r.2.....0A....|
-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..|
-00000080  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000090  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-000000a0  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-000000b0  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000c0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000d0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000e0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000f0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-00000100  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-00000110  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000120  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000130  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000140  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000150  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000160  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000170  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000180  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000190  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-000001a0  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-000001b0  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001c0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001d0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001e0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001f0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-00000200  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-00000210  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000220  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000230  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000240  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000250  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000260  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000270  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000280  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000290  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-000002a0  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-000002b0  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002c0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002d0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002e0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002f0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-00000300  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 01 00 04 0e 00  |n8P)l...........|
-00000320  00 00                                             |..|
+00000000  16 03 01 00 51 02 00 00  4d 03 01 1c 0e e9 7a c6  |....Q...M.....z.|
+00000010  91 fe 7e 8c 6f 0b 8e cf  23 f5 07 29 10 de 05 a6  |..~.o...#..)....|
+00000020  20 72 11 65 4f 2b 45 95  96 02 62 20 43 a8 93 34  | r.eO+E...b C..4|
+00000030  e7 c0 29 d5 fb 26 f9 c2  59 37 94 dc e6 b5 c4 ed  |..)..&..Y7......|
+00000040  ae 7a d7 94 d1 f4 d8 0b  02 ad 20 1b 00 05 00 00  |.z........ .....|
+00000050  05 ff 01 00 01 00 16 03  01 02 71 0b 00 02 6d 00  |..........q...m.|
+00000060  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000070  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000080  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000090  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+000000a0  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+000000b0  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000c0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000d0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000e0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000f0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+00000100  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+00000110  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000120  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000130  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000140  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000150  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000160  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000170  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000180  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000190  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+000001a0  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+000001b0  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001c0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001d0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001e0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001f0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+00000200  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+00000210  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f..@....xH.A0.|
+00000220  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000230  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000240  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000250  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H@.-.....|
+00000260  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000270  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000280  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000290  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+000002a0  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+000002b0  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002c0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 01 00  |..A4......9.....|
+000002d0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 01 00 86 10 00 00  82 00 80 6d 51 f3 7f f9  |...........mQ...|
-00000010  3e fb 75 82 41 36 83 e8  6a ee 2a 2e 25 90 67 4c  |>.u.A6..j.*.%.gL|
-00000020  8e 62 2f 30 81 17 e0 85  09 0c 2b b7 23 d7 b0 e2  |.b/0......+.#...|
-00000030  1d f7 3b d7 f5 a1 27 b6  ee 24 b6 1b cc 5b ea 66  |..;...'..$...[.f|
-00000040  0d 6a f4 e5 85 f9 da 43  b4 0e 86 85 e1 f5 aa be  |.j.....C........|
-00000050  c8 ce 39 4c 9c 86 00 08  c2 4b e2 c6 ec 2f f7 ce  |..9L.....K.../..|
-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 4d 1d  d7 8c d6 c7 65 a6 ce af  |.....$M.....e...|
-000000a0  e7 59 0d 7e dc d9 96 1c  ed 9c 57 94 84 b8 3f b5  |.Y.~......W...?.|
-000000b0  34 e1 61 a5 61 f3 5d 09  bc ff                    |4.a.a.]...|
+00000000  16 03 01 00 86 10 00 00  82 00 80 73 bd 73 65 92  |...........s.se.|
+00000010  86 23 41 14 79 7f d5 c1  10 ce 94 4d ad 9c c3 a9  |.#A.y......M....|
+00000020  87 b5 32 52 f8 6b 11 93  2d 9b 98 0b 8b 1d c0 f6  |..2R.k..-.......|
+00000030  53 17 6d c7 9c 2e ae c9  6f cc 99 23 38 37 1a 10  |S.m.....o..#87..|
+00000040  fe 05 0b b5 55 0a 14 e9  60 7d 70 26 98 e2 54 d9  |....U...`}p&..T.|
+00000050  65 cf 2e f4 53 5f 1d aa  3a f6 33 7b eb 4c 0e b3  |e...S_..:.3{.L..|
+00000060  ff 5a db 36 2a 47 f3 df  f9 fc f5 31 78 83 aa 6b  |.Z.6*G.....1x..k|
+00000070  52 b7 ba 1a 96 bc fa c1  a1 a9 bb 2b f5 38 89 00  |R..........+.8..|
+00000080  4d e5 78 13 4e a4 38 46  42 dc 16 14 03 01 00 01  |M.x.N.8FB.......|
+00000090  01 16 03 01 00 24 ae a9  da 45 6b 5e 76 57 02 62  |.....$...Ek^vW.b|
+000000a0  63 d4 1f 40 bf c9 47 27  a9 7a 24 c0 f0 e9 c2 c4  |c..@..G'.z$.....|
+000000b0  9c 07 84 df ae c7 66 40  d2 b0                    |......f@..|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 24 13 81 89 61 5c  |..........$...a\|
-00000010  fb 0a 9c a1 4b db 94 6b  8b 41 6e 63 d6 aa db 88  |....K..k.Anc....|
-00000020  03 b7 b5 19 b8 12 cf 5e  17 54 79 2f 03 91 7e     |.......^.Ty/..~|
+00000000  14 03 01 00 01 01 16 03  01 00 24 e9 84 92 41 c5  |..........$...A.|
+00000010  31 e1 3c a9 78 18 d1 7b  e1 b1 0b 0a ef 18 54 19  |1.<.x..{......T.|
+00000020  7c ba c7 59 ca c8 7b 4d  c9 f4 ad d6 7b 77 fb     ||..Y..{M....{w.|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 1a b3 2b da  ce 45 ec b2 9d 3b 18 d9  |......+..E...;..|
-00000010  7a cb 99 ea ff 4d 91 b5  48 df 6f 8b 2f 85 c7 15  |z....M..H.o./...|
-00000020  03 01 00 16 19 1c 72 74  36 cf 22 0f a0 a7 18 96  |......rt6.".....|
-00000030  3a 67 cb 22 16 f1 a8 7b  57 37                    |:g."...{W7|
+00000000  17 03 01 00 1a 1a dc 95  e2 4f ec f1 f6 68 9d 15  |.........O...h..|
+00000010  56 d5 7b 06 1a f5 be bb  b1 ca b2 a6 d3 9e 28 15  |V.{...........(.|
+00000020  03 01 00 16 64 fe 4a 37  d3 32 a8 55 38 9e 0f 76  |....d.J7.2.U8..v|
+00000030  50 de e2 2e aa 77 15 2b  e5 21                    |P....w.+.!|
index a4a29306cb7ccd3281f87b758ccbf1829fb2a5c1..87fbe3f40517b93524b2d1ae4a4614b4f2c7bfd1 100644 (file)
@@ -1,19 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 02 00 59 02 00 00  55 03 02 5a 52 92 23 05  |....Y...U..ZR.#.|
-00000010  58 68 b2 1e 77 a2 a8 16  e9 88 85 ea 38 b3 63 c2  |Xh..w.......8.c.|
-00000020  40 f8 de 37 3c d4 b9 51  11 2d d1 20 12 fd 95 b3  |@..7<..Q.-. ....|
-00000030  2a 54 40 c0 23 3a 4e 4e  f6 7b f8 77 04 6e e7 d7  |*T@.#:NN.{.w.n..|
-00000040  3b 9a 45 32 e0 af df aa  ff bf 78 8b c0 09 00 00  |;.E2......x.....|
+00000000  16 03 02 00 59 02 00 00  55 03 02 07 ae a6 e4 1a  |....Y...U.......|
+00000010  f7 7a 0c bc ea 21 0e 86  e3 d0 b4 2c fc d9 97 a3  |.z...!.....,....|
+00000020  8b 29 5f 59 3e a9 06 fb  ca d9 57 20 cd 45 e7 cd  |.)_Y>.....W .E..|
+00000030  6c 4c 56 cd 7c 4c 51 2c  8f 8c 67 a2 05 51 26 f5  |lLV.|LQ,..g..Q&.|
+00000040  17 cc 18 c2 a1 29 94 4b  e2 02 cc 1c c0 09 00 00  |.....).K........|
 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....|
 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 d5 0c 00  00 d1 03 00 17 41 04 c3  |*............A..|
-00000280  55 86 65 95 83 02 4b 69  6e 95 f4 52 46 83 21 86  |U.e...Kin..RF.!.|
-00000290  9e 99 cf 81 d9 b8 20 7a  87 b3 07 48 14 04 20 d9  |...... z...H.. .|
-000002a0  6c 2e 22 5a b5 b4 ef de  15 b3 08 ef 1e 18 ea 67  |l."Z...........g|
-000002b0  eb 45 fd e1 27 43 ed 41  ea 05 7e f3 f9 ee 23 00  |.E..'C.A..~...#.|
-000002c0  8a 30 81 87 02 42 00 b0  9c 06 85 83 b2 bf 42 22  |.0...B........B"|
-000002d0  6e 57 7a 31 fe a9 d9 28  be 0a a9 80 49 a2 14 c1  |nWz1...(....I...|
-000002e0  a9 99 76 b7 f9 76 d0 3c  d3 0c c7 42 34 d7 94 a9  |..v..v.<...B4...|
-000002f0  15 66 7e 6b 83 6e b2 b4  5b 22 c9 4e a0 96 db 2b  |.f~k.n..[".N...+|
-00000300  ad 77 33 1e 4a 5c 2f 2e  02 41 26 0c 1a 5a b4 07  |.w3.J\/..A&..Z..|
-00000310  95 99 ec 0b 5b 2e bb db  0e d5 26 c4 b3 eb c2 30  |....[.....&....0|
-00000320  b0 7b c1 07 97 a0 99 3f  db 4e b0 c4 b8 bb 5e be  |.{.....?.N....^.|
-00000330  2a e4 b3 a4 5c ad d1 d7  7a 2d fb ae 73 ee 0c 1e  |*...\...z-..s...|
-00000340  3b 64 e1 74 14 bc c0 1e  8b f3 26 16 03 02 00 04  |;d.t......&.....|
-00000350  0e 00 00 00                                       |....|
+00000270  2a 16 03 02 00 d6 0c 00  00 d2 03 00 17 41 04 cd  |*............A..|
+00000280  9d 30 75 8d 98 17 b5 1b  2f 4e af ea 69 52 a1 c1  |.0u...../N..iR..|
+00000290  86 73 6a 56 54 f8 ed b6  35 e5 4e 34 a0 6f b1 85  |.sjVT...5.N4.o..|
+000002a0  95 8e be 77 c5 1a 56 9a  59 d1 69 79 ea d6 2b c7  |...w..V.Y.iy..+.|
+000002b0  c1 4a fb bc f8 98 c3 49  1c f3 ce 33 ef 98 20 00  |.J.....I...3.. .|
+000002c0  8b 30 81 88 02 42 00 8b  15 7e 3b 4f 73 b0 8e ca  |.0...B...~;Os...|
+000002d0  67 e0 7c d8 89 70 f1 b2  6b 9c 19 84 fa aa 6e 15  |g.|..p..k.....n.|
+000002e0  8b 46 95 57 d5 ac 79 f3  e8 2a e5 7a a8 1e c3 d7  |.F.W..y..*.z....|
+000002f0  0a b2 02 cd d6 32 34 2f  37 65 41 c8 61 c6 ed e5  |.....24/7eA.a...|
+00000300  d2 6f 0f e8 1a 49 b6 c7  02 42 00 d1 00 f4 05 65  |.o...I...B.....e|
+00000310  dd 43 42 db 8b 0b 95 9d  f5 62 51 e6 58 60 20 9b  |.CB......bQ.X` .|
+00000320  46 84 e6 1f 76 4a 92 42  e4 4d 77 5b 76 a5 78 a0  |F...vJ.B.Mw[v.x.|
+00000330  b0 f0 50 7d f9 4f ca 43  9d c2 50 cb 20 1c 40 52  |..P}.O.C..P. .@R|
+00000340  0f a8 c4 43 7a 9d d5 61  de 26 30 b5 16 03 02 00  |...Cz..a.&0.....|
+00000350  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.|
 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 33 07  8a af e1 94 ef f9 08 3a  |......3........:|
-00000070  33 5f b3 e6 42 07 85 af  40 e2 8b 34 53 62 1a 10  |3_..B...@..4Sb..|
-00000080  bb 08 7e 75 d4 21 12 2d  54 87 33 1c 4e 13 27 72  |..~u.!.-T.3.N.'r|
-00000090  3f 9e 9f cc de 47                                 |?....G|
+00000060  00 00 00 00 00 00 c0 81  e7 e8 40 f3 24 45 ed 74  |..........@.$E.t|
+00000070  86 31 7b 39 d1 3c a2 67  99 28 06 b1 34 b6 3c a6  |.1{9.<.g.(..4.<.|
+00000080  1d ce 39 aa 56 c9 72 0d  f1 e0 c1 5a 51 a0 5d f2  |..9.V.r....ZQ.].|
+00000090  44 4d e6 d7 0e 84                                 |DM....|
 >>> Flow 4 (server to client)
-00000000  14 03 02 00 01 01 16 03  02 00 40 4f 47 0d 43 54  |..........@OG.CT|
-00000010  50 69 3a c8 21 a6 6e 28  78 cc 01 b4 5d eb f7 2b  |Pi:.!.n(x...]..+|
-00000020  8b 7e 26 6e cf 56 98 65  ad bf 0f a0 b4 67 13 70  |.~&n.V.e.....g.p|
-00000030  de b5 b5 91 df d6 df 8c  53 c6 54 3d 5d 98 e4 25  |........S.T=]..%|
-00000040  47 a0 0f 91 c7 08 96 17  48 bd 0f                 |G.......H..|
+00000000  14 03 02 00 01 01 16 03  02 00 40 82 8d c7 e3 7b  |..........@....{|
+00000010  f8 9d 33 a1 c2 08 8c 24  d9 af 66 64 6e e8 61 8e  |..3....$..fdn.a.|
+00000020  3c 03 65 2d c3 64 a2 26  23 a5 25 3f a2 a4 f9 40  |<.e-.d.&#.%?...@|
+00000030  ec 9f 0e b8 57 b1 5f 84  ea 94 72 1a 3e 60 f1 dd  |....W._...r.>`..|
+00000040  af 2e 81 f7 16 de 43 85  21 51 49                 |......C.!QI|
 >>> 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 4e fe 12  d7 4b d7 3f 86 5a 2c f6  |.....N...K.?.Z,.|
-00000020  86 03 2a bd 1a 98 d7 bb  9f 59 6c 6d 4d 57 b0 50  |..*......YlmMW.P|
-00000030  d6 97 7e d4 b6 15 03 02  00 30 00 00 00 00 00 00  |..~......0......|
-00000040  00 00 00 00 00 00 00 00  00 00 65 8b b5 ae 86 90  |..........e.....|
-00000050  00 4e 1e 3f bc ac ed 49  f4 5e 73 49 e6 d8 37 83  |.N.?...I.^sI..7.|
-00000060  cf 4f e5 7b 5e c9 1d c8  c9 dc                    |.O.{^.....|
+00000010  00 00 00 00 00 43 8f 88  82 c8 e1 55 37 76 d7 a5  |.....C.....U7v..|
+00000020  83 c6 d2 94 26 fe 30 1f  e2 24 ca d7 27 22 33 47  |....&.0..$..'"3G|
+00000030  5f a9 74 9d ad 15 03 02  00 30 00 00 00 00 00 00  |_.t......0......|
+00000040  00 00 00 00 00 00 00 00  00 00 49 8e ee 5c ec 86  |..........I..\..|
+00000050  e7 64 a7 ac 0d 5c c4 43  a6 45 a4 22 b7 3d 21 06  |.d...\.C.E.".=!.|
+00000060  11 67 08 99 9a 08 a1 7c  e0 1e                    |.g.....|..|
index 103f1d8a11d1d3a3d8c42b3630d8caf3563e3ccf..75816429d1a628b6cdc5138206681bfd114381e9 100644 (file)
@@ -1,78 +1,73 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 02 00 59 02 00 00  55 03 02 e3 ed 49 27 a3  |....Y...U....I'.|
-00000010  28 c5 8c 30 27 c2 ed 57  9b f7 37 a1 6d 2b 88 c2  |(..0'..W..7.m+..|
-00000020  df a7 2d 01 01 00 9a 09  da c2 1f 20 ee 33 87 03  |..-........ .3..|
-00000030  28 93 1c 16 99 5b b1 e0  bf 87 e8 77 4a 72 c9 92  |(....[.....wJr..|
-00000040  8a bc b2 3e 24 e1 f6 e8  f4 3f a2 24 c0 13 00 00  |...>$....?.$....|
+00000000  16 03 02 00 59 02 00 00  55 03 02 0c 74 28 d1 02  |....Y...U...t(..|
+00000010  15 8f 15 9c ec 8c 4e 34  97 d8 14 ab 0c ed 1b 38  |......N4.......8|
+00000020  af 7f e6 d3 41 db fd ad  a0 8d 4f 20 03 71 4a d6  |....A.....O .qJ.|
+00000030  32 23 57 6c e1 55 34 1d  48 6f 9d e0 9a db 15 9d  |2#Wl.U4.Ho......|
+00000040  5b 45 a7 3e 4e 98 31 7d  f5 d4 b6 36 c0 13 00 00  |[E.>N.1}...6....|
 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..............|
-00000080  a4 8a 7f b8 ca 30 0d 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
-00000090  01 05 05 00 30 45 31 0b  30 09 06 03 55 04 06 13  |....0E1.0...U...|
-000000a0  02 41 55 31 13 30 11 06  03 55 04 08 13 0a 53 6f  |.AU1.0...U....So|
-000000b0  6d 65 2d 53 74 61 74 65  31 21 30 1f 06 03 55 04  |me-State1!0...U.|
-000000c0  0a 13 18 49 6e 74 65 72  6e 65 74 20 57 69 64 67  |...Internet Widg|
-000000d0  69 74 73 20 50 74 79 20  4c 74 64 30 1e 17 0d 31  |its Pty Ltd0...1|
-000000e0  30 30 34 32 34 30 39 30  39 33 38 5a 17 0d 31 31  |00424090938Z..11|
-000000f0  30 34 32 34 30 39 30 39  33 38 5a 30 45 31 0b 30  |0424090938Z0E1.0|
-00000100  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
-00000110  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
-00000120  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
-00000130  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
-00000140  74 64 30 81 9f 30 0d 06  09 2a 86 48 86 f7 0d 01  |td0..0...*.H....|
-00000150  01 01 05 00 03 81 8d 00  30 81 89 02 81 81 00 bb  |........0.......|
-00000160  79 d6 f5 17 b5 e5 bf 46  10 d0 dc 69 be e6 2b 07  |y......F...i..+.|
-00000170  43 5a d0 03 2d 8a 7a 43  85 b7 14 52 e7 a5 65 4c  |CZ..-.zC...R..eL|
-00000180  2c 78 b8 23 8c b5 b4 82  e5 de 1f 95 3b 7e 62 a5  |,x.#........;~b.|
-00000190  2c a5 33 d6 fe 12 5c 7a  56 fc f5 06 bf fa 58 7b  |,.3...\zV.....X{|
-000001a0  26 3f b5 cd 04 d3 d0 c9  21 96 4a c7 f4 54 9f 5a  |&?......!.J..T.Z|
-000001b0  bf ef 42 71 00 fe 18 99  07 7f 7e 88 7d 7d f1 04  |..Bq......~.}}..|
-000001c0  39 c4 a2 2e db 51 c9 7c  e3 c0 4c 3b 32 66 01 cf  |9....Q.|..L;2f..|
-000001d0  af b1 1d b8 71 9a 1d db  db 89 6b ae da 2d 79 02  |....q.....k..-y.|
-000001e0  03 01 00 01 a3 81 a7 30  81 a4 30 1d 06 03 55 1d  |.......0..0...U.|
-000001f0  0e 04 16 04 14 b1 ad e2  85 5a cf cb 28 db 69 ce  |.........Z..(.i.|
-00000200  23 69 de d3 26 8e 18 88  39 30 75 06 03 55 1d 23  |#i..&...90u..U.#|
-00000210  04 6e 30 6c 80 14 b1 ad  e2 85 5a cf cb 28 db 69  |.n0l......Z..(.i|
-00000220  ce 23 69 de d3 26 8e 18  88 39 a1 49 a4 47 30 45  |.#i..&...9.I.G0E|
-00000230  31 0b 30 09 06 03 55 04  06 13 02 41 55 31 13 30  |1.0...U....AU1.0|
-00000240  11 06 03 55 04 08 13 0a  53 6f 6d 65 2d 53 74 61  |...U....Some-Sta|
-00000250  74 65 31 21 30 1f 06 03  55 04 0a 13 18 49 6e 74  |te1!0...U....Int|
-00000260  65 72 6e 65 74 20 57 69  64 67 69 74 73 20 50 74  |ernet Widgits Pt|
-00000270  79 20 4c 74 64 82 09 00  85 b0 bb a4 8a 7f b8 ca  |y Ltd...........|
-00000280  30 0c 06 03 55 1d 13 04  05 30 03 01 01 ff 30 0d  |0...U....0....0.|
-00000290  06 09 2a 86 48 86 f7 0d  01 01 05 05 00 03 81 81  |..*.H...........|
-000002a0  00 08 6c 45 24 c7 6b b1  59 ab 0c 52 cc f2 b0 14  |..lE$.k.Y..R....|
-000002b0  d7 87 9d 7a 64 75 b5 5a  95 66 e4 c5 2b 8e ae 12  |...zdu.Z.f..+...|
-000002c0  66 1f eb 4f 38 b3 6e 60  d3 92 fd f7 41 08 b5 25  |f..O8.n`....A..%|
-000002d0  13 b1 18 7a 24 fb 30 1d  ba ed 98 b9 17 ec e7 d7  |...z$.0.........|
-000002e0  31 59 db 95 d3 1d 78 ea  50 56 5c d5 82 5a 2d 5a  |1Y....x.PV\..Z-Z|
-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 f7  |.............A..|
-00000330  75 c1 b9 58 a0 7d 50 48  e9 85 79 db 89 76 4c d7  |u..X.}PH..y..vL.|
-00000340  84 5b 94 9a 15 d8 92 32  74 d2 3e ce 76 5a bd 0e  |.[.....2t.>.vZ..|
-00000350  24 e7 a6 d0 77 5d 8e 3d  9f 94 7a ea 15 46 3c 5c  |$...w].=..z..F<\|
-00000360  61 28 76 4a ff 81 97 2b  3a 0c b7 aa b4 0e cb 00  |a(vJ...+:.......|
-00000370  80 19 00 a8 fe 0a ea 35  30 51 a3 77 37 08 68 10  |.......50Q.w7.h.|
-00000380  5a e9 07 2d 83 67 77 4c  3a 25 14 1c 5b c1 2e 80  |Z..-.gwL:%..[...|
-00000390  30 6d ba 26 c1 f9 c6 3e  fc 55 34 8c d2 9f 2b a6  |0m.&...>.U4...+.|
-000003a0  46 0c 9d 58 2c 9c 2b ce  6f 03 d7 49 4e df 21 ce  |F..X,.+.o..IN.!.|
-000003b0  3f 8b 19 fe 3e 71 23 51  c3 ec 30 c8 3e 3c 3c 50  |?...>q#Q..0.><<P|
-000003c0  da 08 52 c0 10 9f e3 4a  be e0 97 aa de 5e 13 22  |..R....J.....^."|
-000003d0  b2 77 ee 5d 2d d4 ff fb  7f c3 1e e7 51 fe fc 4b  |.w.]-.......Q..K|
-000003e0  56 5b 8f 50 ad cc 34 7a  a9 dd 24 0a d0 c7 b9 bf  |V[.P..4z..$.....|
-000003f0  1a 16 03 02 00 04 0e 00  00 00                    |..........|
+00000060  02 02 71 0b 00 02 6d 00  02 6a 00 02 67 30 82 02  |..q...m..j..g0..|
+00000070  63 30 82 01 cc a0 03 02  01 02 02 09 00 a2 73 00  |c0............s.|
+00000080  0c 81 00 cb f3 30 0d 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
+00000090  01 0b 05 00 30 2b 31 17  30 15 06 03 55 04 0a 13  |....0+1.0...U...|
+000000a0  0e 47 6f 6f 67 6c 65 20  54 45 53 54 49 4e 47 31  |.Google TESTING1|
+000000b0  10 30 0e 06 03 55 04 03  13 07 47 6f 20 52 6f 6f  |.0...U....Go Roo|
+000000c0  74 30 1e 17 0d 31 35 30  31 30 31 30 30 30 30 30  |t0...15010100000|
+000000d0  30 5a 17 0d 32 35 30 31  30 31 30 30 30 30 30 30  |0Z..250101000000|
+000000e0  5a 30 26 31 17 30 15 06  03 55 04 0a 13 0e 47 6f  |Z0&1.0...U....Go|
+000000f0  6f 67 6c 65 20 54 45 53  54 49 4e 47 31 0b 30 09  |ogle TESTING1.0.|
+00000100  06 03 55 04 03 13 02 47  6f 30 81 9f 30 0d 06 09  |..U....Go0..0...|
+00000110  2a 86 48 86 f7 0d 01 01  01 05 00 03 81 8d 00 30  |*.H............0|
+00000120  81 89 02 81 81 00 af 87  88 f6 20 1b 95 65 6c 14  |.......... ..el.|
+00000130  ab 44 05 af 3b 45 14 e3  b7 6d fd 00 63 4d 95 7f  |.D..;E...m..cM..|
+00000140  fe 6a 62 35 86 c0 4a f9  18 7c f6 aa 25 5e 7a 64  |.jb5..J..|..%^zd|
+00000150  31 66 00 ba f4 8e 92 af  c7 6b d8 76 d4 f3 5f 41  |1f.......k.v.._A|
+00000160  cb 6e 56 15 97 1b 97 c1  3c 12 39 21 66 3d 2b 16  |.nV.....<.9!f=+.|
+00000170  d1 bc db 1c c0 a7 da b7  ca ad ba da cb d5 21 50  |..............!P|
+00000180  ec de 8d ab d1 6b 81 4b  89 02 f3 c4 be c1 6c 89  |.....k.K......l.|
+00000190  b1 44 84 bd 21 d1 04 7d  9d 16 4d f9 82 15 f6 ef  |.D..!..}..M.....|
+000001a0  fa d6 09 47 f2 fb 02 03  01 00 01 a3 81 93 30 81  |...G..........0.|
+000001b0  90 30 0e 06 03 55 1d 0f  01 01 ff 04 04 03 02 05  |.0...U..........|
+000001c0  a0 30 1d 06 03 55 1d 25  04 16 30 14 06 08 2b 06  |.0...U.%..0...+.|
+000001d0  01 05 05 07 03 01 06 08  2b 06 01 05 05 07 03 02  |........+.......|
+000001e0  30 0c 06 03 55 1d 13 01  01 ff 04 02 30 00 30 19  |0...U.......0.0.|
+000001f0  06 03 55 1d 0e 04 12 04  10 12 50 8d 89 6f 1b d1  |..U.......P..o..|
+00000200  dc 54 4d 6e cb 69 5e 06  f4 30 1b 06 03 55 1d 23  |.TMn.i^..0...U.#|
+00000210  04 14 30 12 80 10 bf 3d  b6 a9 66 f2 b8 40 cf ea  |..0....=..f..@..|
+00000220  b4 03 78 48 1a 41 30 19  06 03 55 1d 11 04 12 30  |..xH.A0...U....0|
+00000230  10 82 0e 65 78 61 6d 70  6c 65 2e 67 6f 6c 61 6e  |...example.golan|
+00000240  67 30 0d 06 09 2a 86 48  86 f7 0d 01 01 0b 05 00  |g0...*.H........|
+00000250  03 81 81 00 92 7c af 91  55 12 18 96 59 31 a6 48  |.....|..U...Y1.H|
+00000260  40 d5 2d d5 ee bb 02 a0  f5 c2 1e 7c 9b b3 30 7d  |@.-........|..0}|
+00000270  3c dc 76 da 4f 3d c0 fa  ae 2d 33 24 6b 03 7b 1b  |<.v.O=...-3$k.{.|
+00000280  67 59 11 21 b5 11 bc 77  b9 d9 e0 6e a8 2d 2e 35  |gY.!...w...n.-.5|
+00000290  fa 64 5f 22 3e 63 10 6b  be ff 14 86 6d 0d f0 15  |.d_">c.k....m...|
+000002a0  31 a8 14 38 1e 3b 84 87  2c cb 98 ed 51 76 b9 b1  |1..8.;..,...Qv..|
+000002b0  4f dd db 9b 84 04 86 40  fa 51 dd ba b4 8d eb e3  |O......@.Q......|
+000002c0  46 de 46 b9 4f 86 c7 f9  a4 c2 41 34 ac cc f6 ea  |F.F.O.....A4....|
+000002d0  b0 ab 39 18 16 03 02 00  cb 0c 00 00 c7 03 00 17  |..9.............|
+000002e0  41 04 2c e8 55 b8 19 d6  cd e5 c7 96 a4 aa 61 af  |A.,.U.........a.|
+000002f0  aa b2 f1 fc b3 ac 9a 90  02 d0 0a 86 61 9a c1 2e  |............a...|
+00000300  3e fd 42 0b ba 07 95 77  2b 92 a2 5b 1f 44 ad 6b  |>.B....w+..[.D.k|
+00000310  78 7a f4 b3 4b 04 d3 d5  2d eb 20 2d 73 02 4c db  |xz..K...-. -s.L.|
+00000320  7e ac 00 80 79 b0 c6 b9  a8 50 e4 bf de 97 c6 1f  |~...y....P......|
+00000330  ae 5f 89 77 6e e4 23 8c  8d 1a 49 f8 d4 92 cf 0d  |._.wn.#...I.....|
+00000340  f0 08 bd 3a 88 9c 55 46  fc be 9e 7c 70 ff 6f 70  |...:..UF...|p.op|
+00000350  7b 94 b3 7b 82 c3 58 53  f7 20 13 3c 83 6e 10 55  |{..{..XS. .<.n.U|
+00000360  9d 51 cb 53 8c 93 dc 0e  02 06 40 d4 df ce 57 e4  |.Q.S......@...W.|
+00000370  e0 9a ba e2 b3 9b 01 98  0e 12 ca e9 96 5b 7a f2  |.............[z.|
+00000380  b1 ac 9c 44 e7 6e 2e c6  51 63 99 68 26 93 ca e2  |...D.n..Qc.h&...|
+00000390  40 31 e5 9a 80 ce 83 8f  ca 80 90 c4 e8 ab 89 b2  |@1..............|
+000003a0  ca d6 30 a5 16 03 02 00  04 0e 00 00 00           |..0..........|
 >>> 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.|
 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 1e 0b  cd 40 fa 0f ed fa 55 74  |.........@....Ut|
-00000070  4e ad 10 d1 b5 e1 41 8c  c0 93 81 38 f3 83 f1 37  |N.....A....8...7|
-00000080  6a d4 6c ea ba 5b 9e 38  d3 c1 bb 41 45 fb f0 48  |j.l..[.8...AE..H|
-00000090  c1 06 31 64 e0 65                                 |..1d.e|
+00000060  00 00 00 00 00 00 7d 87  6f 44 8f b9 92 51 5a b7  |......}.oD...QZ.|
+00000070  d2 6c 22 7f 62 a1 4e 30  61 f8 42 cd b0 05 c0 24  |.l".b.N0a.B....$|
+00000080  1f e0 49 a8 36 ce 8a 68  94 b7 37 c7 e8 d9 d8 05  |..I.6..h..7.....|
+00000090  be fb 5e 48 ba d1                                 |..^H..|
 >>> Flow 4 (server to client)
-00000000  14 03 02 00 01 01 16 03  02 00 40 17 d1 79 f8 e0  |..........@..y..|
-00000010  d4 40 15 85 df 4d a6 d5  60 90 1f d6 52 58 e7 ae  |.@...M..`...RX..|
-00000020  05 eb a2 ea ed c9 be ae  b5 54 39 de 05 66 27 67  |.........T9..f'g|
-00000030  59 07 03 e7 10 f9 3f da  d8 85 8b 2f 7b 33 9f f5  |Y.....?..../{3..|
-00000040  43 50 b9 9c 6e dd 01 ae  d8 c9 1d                 |CP..n......|
+00000000  14 03 02 00 01 01 16 03  02 00 40 7d ed 01 b9 5a  |..........@}...Z|
+00000010  34 f4 e1 63 70 84 13 86  e6 4d 90 92 da 3c 9b 35  |4..cp....M...<.5|
+00000020  77 92 7f 0a fd 69 09 75  30 5b c3 2c 6e 8e d0 59  |w....i.u0[.,n..Y|
+00000030  08 08 5c c9 eb 53 45 f3  a6 12 16 f2 95 06 27 82  |..\..SE.......'.|
+00000040  6d 9b 9e 6a bb 52 79 65  ca 94 9b                 |m..j.Rye...|
 >>> 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 65 81 63  71 55 1c 46 8a 60 46 d9  |.....e.cqU.F.`F.|
-00000020  7d 71 a2 62 b8 a8 3b 06  3d a2 f4 53 a4 46 a8 9e  |}q.b..;.=..S.F..|
-00000030  b7 89 8a 42 ce 15 03 02  00 30 00 00 00 00 00 00  |...B.....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 7a 78 a4 e7 2f 40  |..........zx../@|
-00000050  df 42 9b 76 7a 45 0a 86  40 af 3c 40 c6 69 ba e1  |.B.vzE..@.<@.i..|
-00000060  23 82 fa 44 fd 73 fc 5b  f7 b9                    |#..D.s.[..|
+00000010  00 00 00 00 00 bb 2d 28  50 1f a4 8f be 94 b9 99  |......-(P.......|
+00000020  e6 0b dd cf 50 fc 72 92  ec 1d 72 9b 27 9a 36 18  |....P.r...r.'.6.|
+00000030  3e e3 d7 cc 69 15 03 02  00 30 00 00 00 00 00 00  |>...i....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 61 ca 39 3c 7e 9f  |..........a.9<~.|
+00000050  1c c8 c2 2a 42 4a d0 c4  f3 80 41 04 b4 35 d0 41  |...*BJ....A..5.A|
+00000060  3d 47 1b 16 2c 71 27 04  7c 81                    |=G..,q'.|.|
index 729391f68ca4945720fa9e49d84b6ff4972ec85a..e5e315e255ac04a4c4ae5e9312f5cc4379cf883e 100644 (file)
@@ -1,84 +1,79 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 02 00 51 02 00 00  4d 03 02 7e 38 ae 3c 50  |....Q...M..~8.<P|
-00000010  03 96 3d 54 2f cd 86 21  98 7f 87 43 d8 58 aa a3  |..=T/..!...C.X..|
-00000020  d5 9f e7 25 a6 ab 34 7f  10 5f 99 20 56 c5 a8 dd  |...%..4.._. V...|
-00000030  37 17 0d 51 f1 0d c4 4e  76 0f 01 26 56 c9 0c 20  |7..Q...Nv..&V.. |
-00000040  28 ef cd ac 38 ea d3 7f  6f aa 7c b8 00 05 00 00  |(...8...o.|.....|
-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..|
-00000080  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000090  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-000000a0  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-000000b0  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000c0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000d0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000e0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000f0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-00000100  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-00000110  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000120  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000130  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000140  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000150  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000160  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000170  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000180  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000190  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-000001a0  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-000001b0  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001c0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001d0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001e0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001f0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-00000200  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-00000210  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000220  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000230  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000240  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000250  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000260  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000270  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000280  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000290  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-000002a0  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-000002b0  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002c0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002d0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002e0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002f0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-00000300  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 02 00 04 0e 00  |n8P)l...........|
-00000320  00 00                                             |..|
+00000000  16 03 02 00 51 02 00 00  4d 03 02 59 22 be 64 85  |....Q...M..Y".d.|
+00000010  71 af 54 70 5f a8 50 ff  68 52 a0 9e a7 79 4d 90  |q.Tp_.P.hR...yM.|
+00000020  cd bc c7 9c 4f 62 bc 4d  a6 b9 0c 20 e1 94 8f 01  |....Ob.M... ....|
+00000030  fa 7f 9e 6f 01 72 82 ef  cc 41 ed 4d 7e 76 ee e1  |...o.r...A.M~v..|
+00000040  21 34 f3 5c e0 b4 4b e2  73 37 a8 40 00 05 00 00  |!4.\..K.s7.@....|
+00000050  05 ff 01 00 01 00 16 03  02 02 71 0b 00 02 6d 00  |..........q...m.|
+00000060  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000070  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000080  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000090  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+000000a0  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+000000b0  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000c0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000d0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000e0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000f0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+00000100  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+00000110  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000120  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000130  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000140  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000150  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000160  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000170  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000180  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000190  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+000001a0  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+000001b0  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001c0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001d0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001e0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001f0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+00000200  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+00000210  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f..@....xH.A0.|
+00000220  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000230  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000240  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000250  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H@.-.....|
+00000260  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000270  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000280  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000290  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+000002a0  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+000002b0  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002c0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 02 00  |..A4......9.....|
+000002d0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 02 00 86 10 00 00  82 00 80 6d 51 f3 7f f9  |...........mQ...|
-00000010  3e fb 75 82 41 36 83 e8  6a ee 2a 2e 25 90 67 4c  |>.u.A6..j.*.%.gL|
-00000020  8e 62 2f 30 81 17 e0 85  09 0c 2b b7 23 d7 b0 e2  |.b/0......+.#...|
-00000030  1d f7 3b d7 f5 a1 27 b6  ee 24 b6 1b cc 5b ea 66  |..;...'..$...[.f|
-00000040  0d 6a f4 e5 85 f9 da 43  b4 0e 86 85 e1 f5 aa be  |.j.....C........|
-00000050  c8 ce 39 4c 9c 86 00 08  c2 4b e2 c6 ec 2f f7 ce  |..9L.....K.../..|
-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 b9 df  85 a1 6d a7 14 b5 bc f5  |.....$....m.....|
-000000a0  c2 1d 40 fc 1e 19 f2 36  2d ec 6b 59 c5 6d ae c7  |..@....6-.kY.m..|
-000000b0  1c ad 7e a3 5b 4d 12 e5  58 5a                    |..~.[M..XZ|
+00000000  16 03 02 00 86 10 00 00  82 00 80 73 bd 73 65 92  |...........s.se.|
+00000010  86 23 41 14 79 7f d5 c1  10 ce 94 4d ad 9c c3 a9  |.#A.y......M....|
+00000020  87 b5 32 52 f8 6b 11 93  2d 9b 98 0b 8b 1d c0 f6  |..2R.k..-.......|
+00000030  53 17 6d c7 9c 2e ae c9  6f cc 99 23 38 37 1a 10  |S.m.....o..#87..|
+00000040  fe 05 0b b5 55 0a 14 e9  60 7d 70 26 98 e2 54 d9  |....U...`}p&..T.|
+00000050  65 cf 2e f4 53 5f 1d aa  3a f6 33 7b eb 4c 0e b3  |e...S_..:.3{.L..|
+00000060  ff 5a db 36 2a 47 f3 df  f9 fc f5 31 78 83 aa 6b  |.Z.6*G.....1x..k|
+00000070  52 b7 ba 1a 96 bc fa c1  a1 a9 bb 2b f5 38 89 00  |R..........+.8..|
+00000080  4d e5 78 13 4e a4 38 46  42 dc 16 14 03 02 00 01  |M.x.N.8FB.......|
+00000090  01 16 03 02 00 24 0b 7b  3e 32 fb 94 95 66 26 a9  |.....$.{>2...f&.|
+000000a0  4c 21 5e 18 59 cb 80 57  1b 9a 89 c8 91 c5 30 1f  |L!^.Y..W......0.|
+000000b0  1a e2 80 9a 0f 03 8e 7b  4c 7d                    |.......{L}|
 >>> Flow 4 (server to client)
-00000000  14 03 02 00 01 01 16 03  02 00 24 a3 f3 22 a8 32  |..........$..".2|
-00000010  63 c3 88 5c 0f fb 2d 47  21 0d 62 e2 db aa ed ae  |c..\..-G!.b.....|
-00000020  b6 5f e3 c8 98 fc 91 5e  04 83 cf c3 21 17 ce     |._.....^....!..|
+00000000  14 03 02 00 01 01 16 03  02 00 24 06 7f be 82 45  |..........$....E|
+00000010  79 c6 67 fb d3 1e 3f ca  d9 0f 8f 81 36 cc 80 77  |y.g...?.....6..w|
+00000020  b8 48 f3 88 29 fa f1 3a  b2 d4 fd 10 e5 8c 43     |.H..)..:......C|
 >>> Flow 5 (client to server)
-00000000  17 03 02 00 1a f1 e4 46  c7 14 91 4b c6 25 fd aa  |.......F...K.%..|
-00000010  5d dd 3f 61 ac 9c 79 68  bc e6 0f a1 e4 f3 73 15  |].?a..yh......s.|
-00000020  03 02 00 16 6b 8d 23 3c  99 b4 c2 23 3c 27 fd 41  |....k.#<...#<'.A|
-00000030  cc 04 e5 fc e7 f9 d9 81  0a b8                    |..........|
+00000000  17 03 02 00 1a 29 4d a2  80 38 2c 9e 96 bb 29 8b  |.....)M..8,...).|
+00000010  22 69 ea 85 3e d8 a9 66  39 b8 58 12 ae 67 db 15  |"i..>..f9.X..g..|
+00000020  03 02 00 16 8c b2 f4 c1  35 5d 28 dc 5c bc 30 95  |........5](.\.0.|
+00000030  99 3e f6 c6 ff 4f 5c f4  85 1a                    |.>...O\...|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256 b/libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256
new file mode 100644 (file)
index 0000000..9e41089
--- /dev/null
@@ -0,0 +1,81 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 51 02 00 00  4d 03 03 e7 18 39 61 14  |....Q...M....9a.|
+00000010  47 69 40 34 ae 4e 58 4b  32 2d ed 2a 52 09 c5 2f  |Gi@4.NXK2-.*R../|
+00000020  07 f6 44 0b 2b 9c 43 4b  bb 79 b6 20 48 f4 ff f1  |..D.+.CK.y. H...|
+00000030  c6 72 77 e5 3a e0 8d 08  b9 cd 8b bf e3 9b ec 41  |.rw.:..........A|
+00000040  1d d9 86 1b 35 7b 8c 04  e0 83 0d d3 00 9c 00 00  |....5{..........|
+00000050  05 ff 01 00 01 00 16 03  03 02 71 0b 00 02 6d 00  |..........q...m.|
+00000060  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000070  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000080  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000090  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+000000a0  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+000000b0  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000c0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000d0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000e0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000f0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+00000100  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+00000110  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000120  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000130  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000140  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000150  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000160  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000170  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000180  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000190  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+000001a0  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+000001b0  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001c0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001d0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001e0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001f0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+00000200  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+00000210  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f..@....xH.A0.|
+00000220  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000230  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000240  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000250  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H@.-.....|
+00000260  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000270  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000280  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000290  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+000002a0  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+000002b0  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002c0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
+000002d0  04 0e 00 00 00                                    |.....|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 86 10 00 00  82 00 80 73 bd 73 65 92  |...........s.se.|
+00000010  86 23 41 14 79 7f d5 c1  10 ce 94 4d ad 9c c3 a9  |.#A.y......M....|
+00000020  87 b5 32 52 f8 6b 11 93  2d 9b 98 0b 8b 1d c0 f6  |..2R.k..-.......|
+00000030  53 17 6d c7 9c 2e ae c9  6f cc 99 23 38 37 1a 10  |S.m.....o..#87..|
+00000040  fe 05 0b b5 55 0a 14 e9  60 7d 70 26 98 e2 54 d9  |....U...`}p&..T.|
+00000050  65 cf 2e f4 53 5f 1d aa  3a f6 33 7b eb 4c 0e b3  |e...S_..:.3{.L..|
+00000060  ff 5a db 36 2a 47 f3 df  f9 fc f5 31 78 83 aa 6b  |.Z.6*G.....1x..k|
+00000070  52 b7 ba 1a 96 bc fa c1  a1 a9 bb 2b f5 38 89 00  |R..........+.8..|
+00000080  4d e5 78 13 4e a4 38 46  42 dc 16 14 03 03 00 01  |M.x.N.8FB.......|
+00000090  01 16 03 03 00 28 00 00  00 00 00 00 00 00 8a 9b  |.....(..........|
+000000a0  29 1d 64 2e ee 0d 39 d9  c5 86 b9 02 9d c3 bd 74  |).d...9........t|
+000000b0  39 9d 53 9f 1a ee 84 64  82 82 41 81 f8 2f        |9.S....d..A../|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 28 60 71 25 f9 f9  |..........(`q%..|
+00000010  89 cd f8 6f 00 a6 0e 92  f8 3e 84 08 79 6f 91 cd  |...o.....>..yo..|
+00000020  e2 62 d5 da 96 79 c3 0d  f4 34 26 bd 47 9c 30 aa  |.b...y...4&.G.0.|
+00000030  1b 5f 24                                          |._$|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 44 05 c9  |.............D..|
+00000010  2b 82 55 26 ab 4b 65 b1  94 e5 8a 81 bf 44 a5 cb  |+.U&.Ke......D..|
+00000020  22 f0 0a 15 03 03 00 1a  00 00 00 00 00 00 00 02  |"...............|
+00000030  59 8d 6f 5d 30 47 4d 3e  ed aa 87 5f ca 39 44 a4  |Y.o]0GM>..._.9D.|
+00000040  9b fc                                             |..|
diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384 b/libgo/go/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384
new file mode 100644 (file)
index 0000000..33fb708
--- /dev/null
@@ -0,0 +1,81 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 51 02 00 00  4d 03 03 08 e2 40 1b 1a  |....Q...M....@..|
+00000010  54 dc 66 60 e1 e0 8d 94  c6 dd 2c eb 95 e0 e9 2f  |T.f`......,..../|
+00000020  fb 49 17 d8 34 d7 a2 7a  1b e1 60 20 26 a3 4b 7c  |.I..4..z..` &.K||
+00000030  40 cc df 4b 9c 72 a9 e6  61 89 1e 20 b2 e5 e3 1e  |@..K.r..a.. ....|
+00000040  4e a3 b6 32 ce fc 94 0d  ab 13 74 f8 00 9d 00 00  |N..2......t.....|
+00000050  05 ff 01 00 01 00 16 03  03 02 71 0b 00 02 6d 00  |..........q...m.|
+00000060  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000070  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000080  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000090  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+000000a0  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+000000b0  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000c0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000d0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000e0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000f0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+00000100  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+00000110  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000120  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000130  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000140  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000150  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000160  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000170  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000180  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000190  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+000001a0  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+000001b0  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001c0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001d0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001e0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001f0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+00000200  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+00000210  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f..@....xH.A0.|
+00000220  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000230  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000240  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000250  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H@.-.....|
+00000260  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000270  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000280  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000290  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+000002a0  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+000002b0  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002c0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
+000002d0  04 0e 00 00 00                                    |.....|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 86 10 00 00  82 00 80 73 bd 73 65 92  |...........s.se.|
+00000010  86 23 41 14 79 7f d5 c1  10 ce 94 4d ad 9c c3 a9  |.#A.y......M....|
+00000020  87 b5 32 52 f8 6b 11 93  2d 9b 98 0b 8b 1d c0 f6  |..2R.k..-.......|
+00000030  53 17 6d c7 9c 2e ae c9  6f cc 99 23 38 37 1a 10  |S.m.....o..#87..|
+00000040  fe 05 0b b5 55 0a 14 e9  60 7d 70 26 98 e2 54 d9  |....U...`}p&..T.|
+00000050  65 cf 2e f4 53 5f 1d aa  3a f6 33 7b eb 4c 0e b3  |e...S_..:.3{.L..|
+00000060  ff 5a db 36 2a 47 f3 df  f9 fc f5 31 78 83 aa 6b  |.Z.6*G.....1x..k|
+00000070  52 b7 ba 1a 96 bc fa c1  a1 a9 bb 2b f5 38 89 00  |R..........+.8..|
+00000080  4d e5 78 13 4e a4 38 46  42 dc 16 14 03 03 00 01  |M.x.N.8FB.......|
+00000090  01 16 03 03 00 28 00 00  00 00 00 00 00 00 28 9a  |.....(........(.|
+000000a0  46 23 21 fa a9 ec 6d 57  d1 27 2f 53 58 a9 00 48  |F#!...mW.'/SX..H|
+000000b0  7e 82 82 b8 23 f3 c4 a8  d3 2c a3 99 76 2e        |~...#....,..v.|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 28 0c c8 0a e1 b8  |..........(.....|
+00000010  95 b9 84 bc 0f 48 eb d4  4a a5 63 c2 92 58 8a 91  |.....H..J.c..X..|
+00000020  27 30 36 28 23 f5 50 bd  d6 a9 e9 61 54 10 f9 72  |'06(#.P....aT..r|
+00000030  98 d1 0e                                          |...|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 b9 55 ce  |..............U.|
+00000010  5a ab 7e 7e 58 4f c9 5a  bc 0e 93 98 4f 87 86 98  |Z.~~XO.Z....O...|
+00000020  a6 40 7e 15 03 03 00 1a  00 00 00 00 00 00 00 02  |.@~.............|
+00000030  57 0c 6f d9 28 87 d4 a6  de 14 91 a7 79 cc 19 e5  |W.o.(.......y...|
+00000040  28 66                                             |(f|
index 9ecb065f09218b7d53f832181b4a78954712e016..d7745dc295c3923c103a39497955b0da95c1cf9c 100644 (file)
@@ -1,97 +1,93 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 99 01 00 00  95 03 03 00 00 00 00 00  |................|
+00000000  16 03 01 00 9d 01 00 00  99 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 4e  |...../.5.......N|
-00000050  33 74 00 00 00 05 00 05  01 00 00 00 00 00 0a 00  |3t..............|
-00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
-00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
-00000080  03 ff 01 00 01 00 00 10  00 10 00 0e 06 70 72 6f  |.............pro|
-00000090  74 6f 32 06 70 72 6f 74  6f 31 00 12 00 00        |to2.proto1....|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 4e 33 74 00 00  00 05 00 05 01 00 00 00  |...N3t..........|
+00000060  00 00 0a 00 08 00 06 00  17 00 18 00 19 00 0b 00  |................|
+00000070  02 01 00 00 0d 00 0e 00  0c 04 01 04 03 05 01 05  |................|
+00000080  03 02 01 02 03 ff 01 00  01 00 00 10 00 10 00 0e  |................|
+00000090  06 70 72 6f 74 6f 32 06  70 72 6f 74 6f 31 00 12  |.proto2.proto1..|
+000000a0  00 00                                             |..|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 66 02 00 00  62 03 03 56 83 34 0f 9e  |....f...b..V.4..|
-00000010  dd 02 1c 4f 4f 09 d0 2c  df e6 c1 d2 4a c0 6a e7  |...OO..,....J.j.|
-00000020  1e 65 51 c2 42 01 05 70  4a 6c 97 20 0f a8 fb d8  |.eQ.B..pJl. ....|
-00000030  2f 0f 75 21 17 f8 dd 63  28 4a 18 f6 b1 e5 6f 7c  |/.u!...c(J....o||
-00000040  1d 09 d4 13 bf 66 3a bd  c5 48 14 fc c0 2f 00 00  |.....f:..H.../..|
+00000000  16 03 03 00 66 02 00 00  62 03 03 a2 7d b9 7c f9  |....f...b...}.|.|
+00000010  bf fb cb b2 d5 11 c0 99  19 73 3d b4 eb 6b 39 f8  |.........s=..k9.|
+00000020  1b 7c 1d 6b 17 4d 66 a3  ed 20 5b 20 ee 87 d7 1f  |.|.k.Mf.. [ ....|
+00000030  cf 60 6c 75 12 8b de 56  f6 ca da 4a 92 76 49 43  |.`lu...V...J.vIC|
+00000040  70 18 0a e7 7b 2a 0c f3  44 a6 d8 dd c0 2f 00 00  |p...{*..D..../..|
 00000050  1a ff 01 00 01 00 00 0b  00 04 03 00 01 02 00 10  |................|
-00000060  00 09 00 07 06 70 72 6f  74 6f 31 16 03 03 02 be  |.....proto1.....|
-00000070  0b 00 02 ba 00 02 b7 00  02 b4 30 82 02 b0 30 82  |..........0...0.|
-00000080  02 19 a0 03 02 01 02 02  09 00 85 b0 bb a4 8a 7f  |................|
-00000090  b8 ca 30 0d 06 09 2a 86  48 86 f7 0d 01 01 05 05  |..0...*.H.......|
-000000a0  00 30 45 31 0b 30 09 06  03 55 04 06 13 02 41 55  |.0E1.0...U....AU|
-000000b0  31 13 30 11 06 03 55 04  08 13 0a 53 6f 6d 65 2d  |1.0...U....Some-|
-000000c0  53 74 61 74 65 31 21 30  1f 06 03 55 04 0a 13 18  |State1!0...U....|
-000000d0  49 6e 74 65 72 6e 65 74  20 57 69 64 67 69 74 73  |Internet Widgits|
-000000e0  20 50 74 79 20 4c 74 64  30 1e 17 0d 31 30 30 34  | Pty Ltd0...1004|
-000000f0  32 34 30 39 30 39 33 38  5a 17 0d 31 31 30 34 32  |24090938Z..11042|
-00000100  34 30 39 30 39 33 38 5a  30 45 31 0b 30 09 06 03  |4090938Z0E1.0...|
-00000110  55 04 06 13 02 41 55 31  13 30 11 06 03 55 04 08  |U....AU1.0...U..|
-00000120  13 0a 53 6f 6d 65 2d 53  74 61 74 65 31 21 30 1f  |..Some-State1!0.|
-00000130  06 03 55 04 0a 13 18 49  6e 74 65 72 6e 65 74 20  |..U....Internet |
-00000140  57 69 64 67 69 74 73 20  50 74 79 20 4c 74 64 30  |Widgits Pty Ltd0|
-00000150  81 9f 30 0d 06 09 2a 86  48 86 f7 0d 01 01 01 05  |..0...*.H.......|
-00000160  00 03 81 8d 00 30 81 89  02 81 81 00 bb 79 d6 f5  |.....0.......y..|
-00000170  17 b5 e5 bf 46 10 d0 dc  69 be e6 2b 07 43 5a d0  |....F...i..+.CZ.|
-00000180  03 2d 8a 7a 43 85 b7 14  52 e7 a5 65 4c 2c 78 b8  |.-.zC...R..eL,x.|
-00000190  23 8c b5 b4 82 e5 de 1f  95 3b 7e 62 a5 2c a5 33  |#........;~b.,.3|
-000001a0  d6 fe 12 5c 7a 56 fc f5  06 bf fa 58 7b 26 3f b5  |...\zV.....X{&?.|
-000001b0  cd 04 d3 d0 c9 21 96 4a  c7 f4 54 9f 5a bf ef 42  |.....!.J..T.Z..B|
-000001c0  71 00 fe 18 99 07 7f 7e  88 7d 7d f1 04 39 c4 a2  |q......~.}}..9..|
-000001d0  2e db 51 c9 7c e3 c0 4c  3b 32 66 01 cf af b1 1d  |..Q.|..L;2f.....|
-000001e0  b8 71 9a 1d db db 89 6b  ae da 2d 79 02 03 01 00  |.q.....k..-y....|
-000001f0  01 a3 81 a7 30 81 a4 30  1d 06 03 55 1d 0e 04 16  |....0..0...U....|
-00000200  04 14 b1 ad e2 85 5a cf  cb 28 db 69 ce 23 69 de  |......Z..(.i.#i.|
-00000210  d3 26 8e 18 88 39 30 75  06 03 55 1d 23 04 6e 30  |.&...90u..U.#.n0|
-00000220  6c 80 14 b1 ad e2 85 5a  cf cb 28 db 69 ce 23 69  |l......Z..(.i.#i|
-00000230  de d3 26 8e 18 88 39 a1  49 a4 47 30 45 31 0b 30  |..&...9.I.G0E1.0|
-00000240  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
-00000250  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
-00000260  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
-00000270  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
-00000280  74 64 82 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0c 06  |td...........0..|
-00000290  03 55 1d 13 04 05 30 03  01 01 ff 30 0d 06 09 2a  |.U....0....0...*|
-000002a0  86 48 86 f7 0d 01 01 05  05 00 03 81 81 00 08 6c  |.H.............l|
-000002b0  45 24 c7 6b b1 59 ab 0c  52 cc f2 b0 14 d7 87 9d  |E$.k.Y..R.......|
-000002c0  7a 64 75 b5 5a 95 66 e4  c5 2b 8e ae 12 66 1f eb  |zdu.Z.f..+...f..|
-000002d0  4f 38 b3 6e 60 d3 92 fd  f7 41 08 b5 25 13 b1 18  |O8.n`....A..%...|
-000002e0  7a 24 fb 30 1d ba ed 98  b9 17 ec e7 d7 31 59 db  |z$.0.........1Y.|
-000002f0  95 d3 1d 78 ea 50 56 5c  d5 82 5a 2d 5a 5f 33 c4  |...x.PV\..Z-Z_3.|
-00000300  b6 d8 c9 75 90 96 8c 0f  52 98 b5 cd 98 1f 89 20  |...u....R...... |
-00000310  5f f2 a0 1c a3 1b 96 94  dd a9 fd 57 e9 70 e8 26  |_..........W.p.&|
-00000320  6d 71 99 9b 26 6e 38 50  29 6c 90 a7 bd d9 16 03  |mq..&n8P)l......|
-00000330  03 00 cd 0c 00 00 c9 03  00 17 41 04 85 b7 f7 7c  |..........A....||
-00000340  49 4e 97 14 07 51 bc 56  2d 3f cf 1d 29 08 ac 6a  |IN...Q.V-?..)..j|
-00000350  b4 e7 0d 62 d8 fd 4d 03  29 0d f8 6c 36 6f 4d 5f  |...b..M.)..l6oM_|
-00000360  b7 5a 8e 37 3e c2 d9 dc  f4 15 52 e9 87 71 0f e5  |.Z.7>.....R..q..|
-00000370  4e a6 88 0e 54 35 e0 8b  50 91 e1 c4 04 01 00 80  |N...T5..P.......|
-00000380  51 eb f8 d6 52 ba f5 b5  0a 22 5f 91 fe f7 ee 43  |Q...R...."_....C|
-00000390  f8 af 52 b6 27 2c fc 14  e2 fb 41 61 ff 7c b9 be  |..R.',....Aa.|..|
-000003a0  f9 78 be dc 18 32 8c 4d  ef 46 c0 5a a7 91 6a 1b  |.x...2.M.F.Z..j.|
-000003b0  47 78 46 39 47 81 8a 2d  b4 cb fd bb 44 3e a7 b7  |GxF9G..-....D>..|
-000003c0  cc 4e df 17 7b 2b 38 49  fa 9d 9f 4e cd ed f2 16  |.N..{+8I...N....|
-000003d0  03 d9 68 cf c9 5a 08 32  f8 ed 02 30 54 61 f6 c0  |..h..Z.2...0Ta..|
-000003e0  f6 78 bc ad 04 9c 8e 90  7d 3d f5 35 86 aa 6e e9  |.x......}=.5..n.|
-000003f0  a2 9a d3 86 27 9f 2d 6e  ea 6e ad 82 0e aa ef 97  |....'.-n.n......|
-00000400  16 03 03 00 04 0e 00 00  00                       |.........|
+00000060  00 09 00 07 06 70 72 6f  74 6f 31 16 03 03 02 71  |.....proto1....q|
+00000070  0b 00 02 6d 00 02 6a 00  02 67 30 82 02 63 30 82  |...m..j..g0..c0.|
+00000080  01 cc a0 03 02 01 02 02  09 00 a2 73 00 0c 81 00  |...........s....|
+00000090  cb f3 30 0d 06 09 2a 86  48 86 f7 0d 01 01 0b 05  |..0...*.H.......|
+000000a0  00 30 2b 31 17 30 15 06  03 55 04 0a 13 0e 47 6f  |.0+1.0...U....Go|
+000000b0  6f 67 6c 65 20 54 45 53  54 49 4e 47 31 10 30 0e  |ogle TESTING1.0.|
+000000c0  06 03 55 04 03 13 07 47  6f 20 52 6f 6f 74 30 1e  |..U....Go Root0.|
+000000d0  17 0d 31 35 30 31 30 31  30 30 30 30 30 30 5a 17  |..150101000000Z.|
+000000e0  0d 32 35 30 31 30 31 30  30 30 30 30 30 5a 30 26  |.250101000000Z0&|
+000000f0  31 17 30 15 06 03 55 04  0a 13 0e 47 6f 6f 67 6c  |1.0...U....Googl|
+00000100  65 20 54 45 53 54 49 4e  47 31 0b 30 09 06 03 55  |e TESTING1.0...U|
+00000110  04 03 13 02 47 6f 30 81  9f 30 0d 06 09 2a 86 48  |....Go0..0...*.H|
+00000120  86 f7 0d 01 01 01 05 00  03 81 8d 00 30 81 89 02  |............0...|
+00000130  81 81 00 af 87 88 f6 20  1b 95 65 6c 14 ab 44 05  |....... ..el..D.|
+00000140  af 3b 45 14 e3 b7 6d fd  00 63 4d 95 7f fe 6a 62  |.;E...m..cM...jb|
+00000150  35 86 c0 4a f9 18 7c f6  aa 25 5e 7a 64 31 66 00  |5..J..|..%^zd1f.|
+00000160  ba f4 8e 92 af c7 6b d8  76 d4 f3 5f 41 cb 6e 56  |......k.v.._A.nV|
+00000170  15 97 1b 97 c1 3c 12 39  21 66 3d 2b 16 d1 bc db  |.....<.9!f=+....|
+00000180  1c c0 a7 da b7 ca ad ba  da cb d5 21 50 ec de 8d  |...........!P...|
+00000190  ab d1 6b 81 4b 89 02 f3  c4 be c1 6c 89 b1 44 84  |..k.K......l..D.|
+000001a0  bd 21 d1 04 7d 9d 16 4d  f9 82 15 f6 ef fa d6 09  |.!..}..M........|
+000001b0  47 f2 fb 02 03 01 00 01  a3 81 93 30 81 90 30 0e  |G..........0..0.|
+000001c0  06 03 55 1d 0f 01 01 ff  04 04 03 02 05 a0 30 1d  |..U...........0.|
+000001d0  06 03 55 1d 25 04 16 30  14 06 08 2b 06 01 05 05  |..U.%..0...+....|
+000001e0  07 03 01 06 08 2b 06 01  05 05 07 03 02 30 0c 06  |.....+.......0..|
+000001f0  03 55 1d 13 01 01 ff 04  02 30 00 30 19 06 03 55  |.U.......0.0...U|
+00000200  1d 0e 04 12 04 10 12 50  8d 89 6f 1b d1 dc 54 4d  |.......P..o...TM|
+00000210  6e cb 69 5e 06 f4 30 1b  06 03 55 1d 23 04 14 30  |n.i^..0...U.#..0|
+00000220  12 80 10 bf 3d b6 a9 66  f2 b8 40 cf ea b4 03 78  |....=..f..@....x|
+00000230  48 1a 41 30 19 06 03 55  1d 11 04 12 30 10 82 0e  |H.A0...U....0...|
+00000240  65 78 61 6d 70 6c 65 2e  67 6f 6c 61 6e 67 30 0d  |example.golang0.|
+00000250  06 09 2a 86 48 86 f7 0d  01 01 0b 05 00 03 81 81  |..*.H...........|
+00000260  00 92 7c af 91 55 12 18  96 59 31 a6 48 40 d5 2d  |..|..U...Y1.H@.-|
+00000270  d5 ee bb 02 a0 f5 c2 1e  7c 9b b3 30 7d 3c dc 76  |........|..0}<.v|
+00000280  da 4f 3d c0 fa ae 2d 33  24 6b 03 7b 1b 67 59 11  |.O=...-3$k.{.gY.|
+00000290  21 b5 11 bc 77 b9 d9 e0  6e a8 2d 2e 35 fa 64 5f  |!...w...n.-.5.d_|
+000002a0  22 3e 63 10 6b be ff 14  86 6d 0d f0 15 31 a8 14  |">c.k....m...1..|
+000002b0  38 1e 3b 84 87 2c cb 98  ed 51 76 b9 b1 4f dd db  |8.;..,...Qv..O..|
+000002c0  9b 84 04 86 40 fa 51 dd  ba b4 8d eb e3 46 de 46  |....@.Q......F.F|
+000002d0  b9 4f 86 c7 f9 a4 c2 41  34 ac cc f6 ea b0 ab 39  |.O.....A4......9|
+000002e0  18 16 03 03 00 cd 0c 00  00 c9 03 00 17 41 04 41  |.............A.A|
+000002f0  a4 1f 6f ea 6d 59 68 72  1a 6d 47 c7 b4 a0 08 01  |..o.mYhr.mG.....|
+00000300  b9 b3 d8 7a 95 75 c0 58  2a d9 29 91 e7 d9 78 b2  |...z.u.X*.)...x.|
+00000310  97 1d 52 72 2d 18 cb ce  83 8a 07 f4 bd dd 7e a1  |..Rr-.........~.|
+00000320  d2 45 51 9d bf f1 bf 01  33 3a 10 94 6c 2b 99 04  |.EQ.....3:..l+..|
+00000330  01 00 80 63 8f 03 6d b4  4d f7 27 d0 1f f2 0f ff  |...c..m.M.'.....|
+00000340  af 27 c2 97 21 68 8c 32  8b 14 67 0e b5 75 3a 5b  |.'..!h.2..g..u:[|
+00000350  73 08 9a c7 fd ad 8d 50  2a de e7 d6 c5 87 7a b2  |s......P*.....z.|
+00000360  06 29 0a 09 dd d4 81 d5  a7 2b 4d 20 50 72 6f be  |.).......+M Pro.|
+00000370  35 9b c6 2d b0 1e 8f a2  cf 10 33 d4 53 0b 33 95  |5..-......3.S.3.|
+00000380  b8 a5 34 38 1b db 1e 45  07 36 3a 86 c7 f1 b1 3a  |..48...E.6:....:|
+00000390  2e 5d 82 b2 1d 3e e1 27  8f f2 f4 2c 8c c3 27 e9  |.]...>.'...,..'.|
+000003a0  f0 9a 8f 6d 20 b1 19 8e  23 d5 04 69 e4 eb 0d eb  |...m ...#..i....|
+000003b0  97 fb 71 16 03 03 00 04  0e 00 00 00              |..q.........|
 >>> 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 47 18  |.....(........G.|
-00000060  39 03 93 d9 5b 27 29 70  52 68 15 79 f2 60 e6 58  |9...[')pRh.y.`.X|
-00000070  d9 98 cd ce a1 8f 4d ee  2c f0 34 9f fa 73        |......M.,.4..s|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 15 94  |.....(..........|
+00000060  6f 5b 35 9d eb 14 c8 be  23 a7 05 8c 14 86 35 a7  |o[5.....#.....5.|
+00000070  5c 91 76 4f 85 b1 09 f8  0f 58 9f ec d2 a9        |\.vO.....X....|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 39 76 15 70 f1  |..........(9v.p.|
-00000010  73 c9 9a 1e 76 40 bc de  de 49 be 3e 10 4d 6a 42  |s...v@...I.>.MjB|
-00000020  1b 9b bd 07 6b 19 ff f9  2c 19 3c c8 e7 06 fa c8  |....k...,.<.....|
-00000030  3d 52 b4                                          |=R.|
+00000000  14 03 03 00 01 01 16 03  03 00 28 e7 7f 99 c9 fa  |..........(.....|
+00000010  e0 a3 e3 77 68 74 37 62  26 90 d6 be ec a1 ae 5a  |...wht7b&......Z|
+00000020  de af 10 f1 2e a0 42 f0  88 ed 89 54 04 b2 b9 eb  |......B....T....|
+00000030  b0 91 b8                                          |...|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 14 96 ec  |................|
-00000010  f4 bb ae 45 81 0c 39 10  e2 3a 91 51 04 2c 01 a8  |...E..9..:.Q.,..|
-00000020  8b a3 25 15 03 03 00 1a  00 00 00 00 00 00 00 02  |..%.............|
-00000030  fe 1a 53 01 17 ad a1 30  0a 73 17 9f 39 b4 30 ac  |..S....0.s..9.0.|
-00000040  91 ee                                             |..|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 be e7 77  |...............w|
+00000010  f9 92 ac 51 d0 34 25 34  e6 35 9e ea f0 d3 89 45  |...Q.4%4.5.....E|
+00000020  84 1b 93 15 03 03 00 1a  00 00 00 00 00 00 00 02  |................|
+00000030  1a 27 54 01 c9 7c 86 4b  61 c8 98 1b d3 15 1f 93  |.'T..|.Ka.......|
+00000040  f9 42                                             |.B|
index a22ffaeb499ab6c9d2774ac19420947c35f1d851..9a34e4a78bb60a341c55051a1986f0d015c60730 100644 (file)
@@ -1,96 +1,91 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 92 01 00 00  8e 03 03 00 00 00 00 00  |................|
+00000000  16 03 01 00 96 01 00 00  92 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 47  |...../.5.......G|
-00000050  33 74 00 00 00 05 00 05  01 00 00 00 00 00 0a 00  |3t..............|
-00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
-00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
-00000080  03 ff 01 00 01 00 00 10  00 09 00 07 06 70 72 6f  |.............pro|
-00000090  74 6f 33 00 12 00 00                              |to3....|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 47 33 74 00 00  00 05 00 05 01 00 00 00  |...G3t..........|
+00000060  00 00 0a 00 08 00 06 00  17 00 18 00 19 00 0b 00  |................|
+00000070  02 01 00 00 0d 00 0e 00  0c 04 01 04 03 05 01 05  |................|
+00000080  03 02 01 02 03 ff 01 00  01 00 00 10 00 09 00 07  |................|
+00000090  06 70 72 6f 74 6f 33 00  12 00 00                 |.proto3....|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 94 d7 79 73 82  |....Y...U....ys.|
-00000010  87 7c 85 6e 8a 1b 7d bf  69 c9 98 0c 44 bd f6 78  |.|.n..}.i...D..x|
-00000020  d2 80 dc d8 7d 80 bb 91  4b d4 ed 20 fe 9f 2f 7b  |....}...K.. ../{|
-00000030  f2 1a 44 36 cd ce af f1  b5 01 8a ac 18 e4 2b 23  |..D6..........+#|
-00000040  a8 ab 1a 32 23 8b 0b e2  81 a8 0a 40 c0 2f 00 00  |...2#......@./..|
+00000000  16 03 03 00 59 02 00 00  55 03 03 18 3d 15 59 fb  |....Y...U...=.Y.|
+00000010  0a a4 93 d7 43 50 59 7f  6c f9 64 db b5 47 cc 17  |....CPY.l.d..G..|
+00000020  8c cd 91 b5 04 02 3f c0  5d 60 b7 20 75 ed d2 e9  |......?.]`. u...|
+00000030  b6 72 2d f7 66 34 2e 2f  d2 b9 80 66 eb c3 36 f6  |.r-.f4./...f..6.|
+00000040  b2 61 77 79 a9 c2 db cd  57 5a b2 6b c0 2f 00 00  |.awy....WZ.k./..|
 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..............|
-00000080  a4 8a 7f b8 ca 30 0d 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
-00000090  01 05 05 00 30 45 31 0b  30 09 06 03 55 04 06 13  |....0E1.0...U...|
-000000a0  02 41 55 31 13 30 11 06  03 55 04 08 13 0a 53 6f  |.AU1.0...U....So|
-000000b0  6d 65 2d 53 74 61 74 65  31 21 30 1f 06 03 55 04  |me-State1!0...U.|
-000000c0  0a 13 18 49 6e 74 65 72  6e 65 74 20 57 69 64 67  |...Internet Widg|
-000000d0  69 74 73 20 50 74 79 20  4c 74 64 30 1e 17 0d 31  |its Pty Ltd0...1|
-000000e0  30 30 34 32 34 30 39 30  39 33 38 5a 17 0d 31 31  |00424090938Z..11|
-000000f0  30 34 32 34 30 39 30 39  33 38 5a 30 45 31 0b 30  |0424090938Z0E1.0|
-00000100  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
-00000110  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
-00000120  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
-00000130  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
-00000140  74 64 30 81 9f 30 0d 06  09 2a 86 48 86 f7 0d 01  |td0..0...*.H....|
-00000150  01 01 05 00 03 81 8d 00  30 81 89 02 81 81 00 bb  |........0.......|
-00000160  79 d6 f5 17 b5 e5 bf 46  10 d0 dc 69 be e6 2b 07  |y......F...i..+.|
-00000170  43 5a d0 03 2d 8a 7a 43  85 b7 14 52 e7 a5 65 4c  |CZ..-.zC...R..eL|
-00000180  2c 78 b8 23 8c b5 b4 82  e5 de 1f 95 3b 7e 62 a5  |,x.#........;~b.|
-00000190  2c a5 33 d6 fe 12 5c 7a  56 fc f5 06 bf fa 58 7b  |,.3...\zV.....X{|
-000001a0  26 3f b5 cd 04 d3 d0 c9  21 96 4a c7 f4 54 9f 5a  |&?......!.J..T.Z|
-000001b0  bf ef 42 71 00 fe 18 99  07 7f 7e 88 7d 7d f1 04  |..Bq......~.}}..|
-000001c0  39 c4 a2 2e db 51 c9 7c  e3 c0 4c 3b 32 66 01 cf  |9....Q.|..L;2f..|
-000001d0  af b1 1d b8 71 9a 1d db  db 89 6b ae da 2d 79 02  |....q.....k..-y.|
-000001e0  03 01 00 01 a3 81 a7 30  81 a4 30 1d 06 03 55 1d  |.......0..0...U.|
-000001f0  0e 04 16 04 14 b1 ad e2  85 5a cf cb 28 db 69 ce  |.........Z..(.i.|
-00000200  23 69 de d3 26 8e 18 88  39 30 75 06 03 55 1d 23  |#i..&...90u..U.#|
-00000210  04 6e 30 6c 80 14 b1 ad  e2 85 5a cf cb 28 db 69  |.n0l......Z..(.i|
-00000220  ce 23 69 de d3 26 8e 18  88 39 a1 49 a4 47 30 45  |.#i..&...9.I.G0E|
-00000230  31 0b 30 09 06 03 55 04  06 13 02 41 55 31 13 30  |1.0...U....AU1.0|
-00000240  11 06 03 55 04 08 13 0a  53 6f 6d 65 2d 53 74 61  |...U....Some-Sta|
-00000250  74 65 31 21 30 1f 06 03  55 04 0a 13 18 49 6e 74  |te1!0...U....Int|
-00000260  65 72 6e 65 74 20 57 69  64 67 69 74 73 20 50 74  |ernet Widgits Pt|
-00000270  79 20 4c 74 64 82 09 00  85 b0 bb a4 8a 7f b8 ca  |y Ltd...........|
-00000280  30 0c 06 03 55 1d 13 04  05 30 03 01 01 ff 30 0d  |0...U....0....0.|
-00000290  06 09 2a 86 48 86 f7 0d  01 01 05 05 00 03 81 81  |..*.H...........|
-000002a0  00 08 6c 45 24 c7 6b b1  59 ab 0c 52 cc f2 b0 14  |..lE$.k.Y..R....|
-000002b0  d7 87 9d 7a 64 75 b5 5a  95 66 e4 c5 2b 8e ae 12  |...zdu.Z.f..+...|
-000002c0  66 1f eb 4f 38 b3 6e 60  d3 92 fd f7 41 08 b5 25  |f..O8.n`....A..%|
-000002d0  13 b1 18 7a 24 fb 30 1d  ba ed 98 b9 17 ec e7 d7  |...z$.0.........|
-000002e0  31 59 db 95 d3 1d 78 ea  50 56 5c d5 82 5a 2d 5a  |1Y....x.PV\..Z-Z|
-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 7d  |.............A.}|
-00000330  75 a5 53 0b a5 4d a6 81  e0 df c4 11 c9 b5 31 ba  |u.S..M........1.|
-00000340  9f 7b 51 04 57 c6 e0 b9  b0 bc 4f bc 71 74 8a 2e  |.{Q.W.....O.qt..|
-00000350  d1 f6 39 36 94 4e c7 d3  a7 1b 2c b5 55 04 71 01  |..96.N....,.U.q.|
-00000360  9e 2b 42 1e 8b a4 40 b2  13 4f 03 1f 51 9e 5c 04  |.+B...@..O..Q.\.|
-00000370  01 00 80 68 05 c7 4a ca  df 00 85 2b 53 f7 4f c3  |...h..J....+S.O.|
-00000380  b4 0f e8 f7 b8 30 b7 36  56 65 7b 03 6a 72 f1 aa  |.....0.6Ve{.jr..|
-00000390  54 30 90 9e c7 dc fc 03  96 15 70 67 13 12 a4 f4  |T0........pg....|
-000003a0  42 f0 f9 a1 48 c0 44 44  77 0e ea fd cb b5 6e 19  |B...H.DDw.....n.|
-000003b0  89 94 a7 12 67 87 47 19  c3 00 2d c4 9b d4 dc 66  |....g.G...-....f|
-000003c0  fa ca d7 97 79 9b 28 7f  74 d4 37 c0 06 63 d4 9e  |....y.(.t.7..c..|
-000003d0  a1 53 16 5a 8e d7 a5 cc  90 4d 63 f9 0c 18 85 7f  |.S.Z.....Mc.....|
-000003e0  0e 35 3a 49 73 88 82 51  41 e5 2d 58 aa 38 3e bd  |.5:Is..QA.-X.8>.|
-000003f0  3d d8 da 16 03 03 00 04  0e 00 00 00              |=...........|
+00000060  03 02 71 0b 00 02 6d 00  02 6a 00 02 67 30 82 02  |..q...m..j..g0..|
+00000070  63 30 82 01 cc a0 03 02  01 02 02 09 00 a2 73 00  |c0............s.|
+00000080  0c 81 00 cb f3 30 0d 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
+00000090  01 0b 05 00 30 2b 31 17  30 15 06 03 55 04 0a 13  |....0+1.0...U...|
+000000a0  0e 47 6f 6f 67 6c 65 20  54 45 53 54 49 4e 47 31  |.Google TESTING1|
+000000b0  10 30 0e 06 03 55 04 03  13 07 47 6f 20 52 6f 6f  |.0...U....Go Roo|
+000000c0  74 30 1e 17 0d 31 35 30  31 30 31 30 30 30 30 30  |t0...15010100000|
+000000d0  30 5a 17 0d 32 35 30 31  30 31 30 30 30 30 30 30  |0Z..250101000000|
+000000e0  5a 30 26 31 17 30 15 06  03 55 04 0a 13 0e 47 6f  |Z0&1.0...U....Go|
+000000f0  6f 67 6c 65 20 54 45 53  54 49 4e 47 31 0b 30 09  |ogle TESTING1.0.|
+00000100  06 03 55 04 03 13 02 47  6f 30 81 9f 30 0d 06 09  |..U....Go0..0...|
+00000110  2a 86 48 86 f7 0d 01 01  01 05 00 03 81 8d 00 30  |*.H............0|
+00000120  81 89 02 81 81 00 af 87  88 f6 20 1b 95 65 6c 14  |.......... ..el.|
+00000130  ab 44 05 af 3b 45 14 e3  b7 6d fd 00 63 4d 95 7f  |.D..;E...m..cM..|
+00000140  fe 6a 62 35 86 c0 4a f9  18 7c f6 aa 25 5e 7a 64  |.jb5..J..|..%^zd|
+00000150  31 66 00 ba f4 8e 92 af  c7 6b d8 76 d4 f3 5f 41  |1f.......k.v.._A|
+00000160  cb 6e 56 15 97 1b 97 c1  3c 12 39 21 66 3d 2b 16  |.nV.....<.9!f=+.|
+00000170  d1 bc db 1c c0 a7 da b7  ca ad ba da cb d5 21 50  |..............!P|
+00000180  ec de 8d ab d1 6b 81 4b  89 02 f3 c4 be c1 6c 89  |.....k.K......l.|
+00000190  b1 44 84 bd 21 d1 04 7d  9d 16 4d f9 82 15 f6 ef  |.D..!..}..M.....|
+000001a0  fa d6 09 47 f2 fb 02 03  01 00 01 a3 81 93 30 81  |...G..........0.|
+000001b0  90 30 0e 06 03 55 1d 0f  01 01 ff 04 04 03 02 05  |.0...U..........|
+000001c0  a0 30 1d 06 03 55 1d 25  04 16 30 14 06 08 2b 06  |.0...U.%..0...+.|
+000001d0  01 05 05 07 03 01 06 08  2b 06 01 05 05 07 03 02  |........+.......|
+000001e0  30 0c 06 03 55 1d 13 01  01 ff 04 02 30 00 30 19  |0...U.......0.0.|
+000001f0  06 03 55 1d 0e 04 12 04  10 12 50 8d 89 6f 1b d1  |..U.......P..o..|
+00000200  dc 54 4d 6e cb 69 5e 06  f4 30 1b 06 03 55 1d 23  |.TMn.i^..0...U.#|
+00000210  04 14 30 12 80 10 bf 3d  b6 a9 66 f2 b8 40 cf ea  |..0....=..f..@..|
+00000220  b4 03 78 48 1a 41 30 19  06 03 55 1d 11 04 12 30  |..xH.A0...U....0|
+00000230  10 82 0e 65 78 61 6d 70  6c 65 2e 67 6f 6c 61 6e  |...example.golan|
+00000240  67 30 0d 06 09 2a 86 48  86 f7 0d 01 01 0b 05 00  |g0...*.H........|
+00000250  03 81 81 00 92 7c af 91  55 12 18 96 59 31 a6 48  |.....|..U...Y1.H|
+00000260  40 d5 2d d5 ee bb 02 a0  f5 c2 1e 7c 9b b3 30 7d  |@.-........|..0}|
+00000270  3c dc 76 da 4f 3d c0 fa  ae 2d 33 24 6b 03 7b 1b  |<.v.O=...-3$k.{.|
+00000280  67 59 11 21 b5 11 bc 77  b9 d9 e0 6e a8 2d 2e 35  |gY.!...w...n.-.5|
+00000290  fa 64 5f 22 3e 63 10 6b  be ff 14 86 6d 0d f0 15  |.d_">c.k....m...|
+000002a0  31 a8 14 38 1e 3b 84 87  2c cb 98 ed 51 76 b9 b1  |1..8.;..,...Qv..|
+000002b0  4f dd db 9b 84 04 86 40  fa 51 dd ba b4 8d eb e3  |O......@.Q......|
+000002c0  46 de 46 b9 4f 86 c7 f9  a4 c2 41 34 ac cc f6 ea  |F.F.O.....A4....|
+000002d0  b0 ab 39 18 16 03 03 00  cd 0c 00 00 c9 03 00 17  |..9.............|
+000002e0  41 04 62 52 78 76 89 36  e7 b9 a6 cc df 8e f8 c3  |A.bRxv.6........|
+000002f0  52 54 b6 42 9b 68 65 65  27 91 bf 1b 0f 21 ab a9  |RT.B.hee'....!..|
+00000300  f4 00 62 dd 70 25 b8 ec  d0 3d 9b 0c 53 16 6e eb  |..b.p%...=..S.n.|
+00000310  a8 c3 1a ad a9 de ec 27  64 07 e8 9b b8 bf 5a 6c  |.......'d.....Zl|
+00000320  87 f4 04 01 00 80 05 ec  2b f7 2e a4 5e 79 85 6f  |........+...^y.o|
+00000330  64 7a b5 fb 9a e9 f1 12  ae 28 93 4b 6d 8e a0 2f  |dz.......(.Km../|
+00000340  94 bc 38 26 01 64 ab fb  03 c8 3d 17 bc b4 43 09  |..8&.d....=...C.|
+00000350  19 c8 e9 ac 60 40 67 57  71 e3 72 22 cf b1 a7 38  |....`@gWq.r"...8|
+00000360  ac 86 88 9d 47 6f 70 c9  43 82 75 b6 bf 42 4e 72  |....Gop.C.u..BNr|
+00000370  12 48 d1 2b ce 74 02 5d  30 56 66 6f 71 8f 9b 82  |.H.+.t.]0Vfoq...|
+00000380  70 3b 92 5d fb 37 d3 cf  d3 23 27 d2 d5 8d 72 22  |p;.].7...#'...r"|
+00000390  d4 b4 92 6d 64 06 d9 0b  e0 bb 34 eb bf 42 ec 6a  |...md.....4..B.j|
+000003a0  ea e3 56 68 85 a0 16 03  03 00 04 0e 00 00 00     |..Vh...........|
 >>> 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 a8 da  |.....(..........|
-00000060  74 a6 d0 a5 26 86 f3 5f  89 a4 af ac 9c 1a 01 1f  |t...&.._........|
-00000070  89 8a 1c fc cf 68 3e a5  a3 20 1a b3 78 af        |.....h>.. ..x.|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 97 34  |.....(.........4|
+00000060  d5 c2 64 97 f6 a9 f5 60  bc 17 f3 d3 02 3f 42 a8  |..d....`.....?B.|
+00000070  2f ba eb c6 50 3c ec 9b  8d 3b 22 ed ec 35        |/...P<...;"..5|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 1a f2 a9 e8 71  |..........(....q|
-00000010  b2 a6 ca 36 4a ea 55 f6  20 03 fd f7 90 c3 af 30  |...6J.U. ......0|
-00000020  d3 29 c3 d7 1b d6 4d 3e  61 55 94 0d 4e 3e 83 1a  |.)....M>aU..N>..|
-00000030  97 dd 19                                          |...|
+00000000  14 03 03 00 01 01 16 03  03 00 28 9a e5 f5 51 5c  |..........(...Q\|
+00000010  cb be 5d a1 67 cc 55 aa  ba db e7 0a ab 96 3b 33  |..].g.U.......;3|
+00000020  5f 2c 8c 61 20 f1 0d 6e  ce 90 d8 39 27 d7 fb 68  |_,.a ..n...9'..h|
+00000030  d9 dd da                                          |...|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 94 5b 5e  |..............[^|
-00000010  51 a1 52 ee 19 78 78 ef  12 0d 9c 66 bf e2 48 cb  |Q.R..xx....f..H.|
-00000020  f6 00 1e 15 03 03 00 1a  00 00 00 00 00 00 00 02  |................|
-00000030  cd 5d 31 58 d9 5a 12 65  5b c6 7e 4e e2 04 e7 1d  |.]1X.Z.e[.~N....|
-00000040  b1 4c                                             |.L|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 a8 be 7c  |...............||
+00000010  05 48 ea df 62 4a 7a 45  68 e4 dc e6 42 ff 06 f2  |.H..bJzEh...B...|
+00000020  02 33 1a 15 03 03 00 1a  00 00 00 00 00 00 00 02  |.3..............|
+00000030  66 68 f4 de da 69 b4 f9  80 9c 80 c6 46 e5 2b ae  |fh...i......F.+.|
+00000040  0e d1                                             |..|
index 1470ba7a2500e189c64522c4a244b8ec96663434..4b88acff71dd46baa87d76d6206592ec2d2b9185 100644 (file)
@@ -1,19 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 a5 28 60 99 bf  |....Y...U...(`..|
-00000010  c7 54 04 87 60 ad c5 32  f6 bf ed 11 47 de 4d ff  |.T..`..2....G.M.|
-00000020  99 e1 8f 88 f6 af 10 6e  29 74 0a 20 1d 39 cb e0  |.......n)t. .9..|
-00000030  a5 11 fe 8e 23 11 83 c7  a6 53 fc 97 03 9d ff 7c  |....#....S.....||
-00000040  cf 51 ba 41 64 61 38 22  5c c6 4a 04 c0 09 00 00  |.Q.Ada8"\.J.....|
+00000000  16 03 03 00 59 02 00 00  55 03 03 f0 5c 85 c8 ff  |....Y...U...\...|
+00000010  c5 57 76 99 3d 75 e6 2e  db 31 26 c0 0c 81 c5 6b  |.Wv.=u...1&....k|
+00000020  30 79 e6 72 86 77 48 01  ec 43 1a 20 f8 fd ad b5  |0y.r.wH..C. ....|
+00000030  a0 7b f3 35 27 df ad 95  f9 56 f9 79 6c a2 6c 23  |.{.5'....V.yl.l#|
+00000040  51 4c ef fc 92 fb fa 59  97 e9 63 27 c0 09 00 00  |QL.....Y..c'....|
 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....|
 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 d7 0c 00  00 d3 03 00 17 41 04 c4  |*............A..|
-00000280  0a 40 05 84 eb 90 3c 13  d0 90 af 69 fa 5c 20 75  |.@....<....i.\ u|
-00000290  e1 9b f2 30 f7 df cc 75  2c 35 7e 38 16 99 7d 57  |...0...u,5~8..}W|
-000002a0  6d d7 f0 93 2d 1d c8 03  89 6e 52 3b 20 e5 8a 5f  |m...-....nR; .._|
-000002b0  6d ca 6e 6a ca 51 f8 a4  dc 1d ec 3e 73 c9 72 04  |m.nj.Q.....>s.r.|
-000002c0  03 00 8a 30 81 87 02 41  37 bf 0d 1d c1 9a 37 39  |...0...A7.....79|
-000002d0  4d 4a f8 17 50 5d 4c 78  d4 25 99 9d 81 48 98 a8  |MJ..P]Lx.%...H..|
-000002e0  ff 2d 3f 98 4b 9f d8 96  2b fa 37 cc e8 66 25 0e  |.-?.K...+.7..f%.|
-000002f0  d3 5e 53 c5 3b ad 17 3f  21 ce d2 45 d8 93 95 6c  |.^S.;..?!..E...l|
-00000300  25 f9 5a 10 9f 37 c8 14  a6 02 42 00 e6 bd 9a 89  |%.Z..7....B.....|
-00000310  8e 73 40 f4 90 e6 d8 e2  98 51 10 23 fb 98 e5 47  |.s@......Q.#...G|
-00000320  0c 2a 7a 2f 02 66 a8 20  e4 cb 4f ba 14 1d 9e 3a  |.*z/.f. ..O....:|
-00000330  2f 09 47 44 02 e0 9f 30  21 71 f0 99 09 de 23 d2  |/.GD...0!q....#.|
-00000340  f5 f0 b2 93 70 a3 8f 79  b9 4f 88 0b 35 16 03 03  |....p..y.O..5...|
-00000350  00 2e 0d 00 00 26 03 01  02 40 00 1e 06 01 06 02  |.....&...@......|
-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 00 00 0e 00 00 00  |................|
+00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 51  |*............A.Q|
+00000280  1e 2e 40 c5 a1 13 15 f0  bc 8a 04 e1 9a 57 74 10  |..@..........Wt.|
+00000290  7e b3 17 bf 0c c9 85 9b  5f bd 6b 39 c7 a6 c0 50  |~......._.k9...P|
+000002a0  0e 5e 9b b1 8c cc 57 39  e8 0f 94 02 be 28 19 16  |.^....W9.....(..|
+000002b0  94 73 2b c1 3c a7 0f c9  e7 b0 89 ac 13 53 f9 04  |.s+.<........S..|
+000002c0  03 00 8b 30 81 88 02 42  01 1b e0 ab 94 02 aa 27  |...0...B.......'|
+000002d0  fa 7b 99 9c 68 36 d8 2d  2e e0 92 84 c7 7b 37 74  |.{..h6.-.....{7t|
+000002e0  6a ad a8 f5 50 3f 74 d5  e8 8e 5a db 31 43 c8 98  |j...P?t...Z.1C..|
+000002f0  d3 ee 61 43 80 9a 72 eb  2d 2b 21 b8 33 aa 61 0a  |..aC..r.-+!.3.a.|
+00000300  cd dc 85 88 29 26 83 ee  3c b2 02 42 00 b6 ea 34  |....)&..<..B...4|
+00000310  30 71 5c 0a 9a 6d a2 25  62 1c 3e 13 90 9c a3 b8  |0q\..m.%b.>.....|
+00000320  0d 97 a8 06 26 9e 31 50  88 9a b9 ff 12 63 a8 14  |....&.1P.....c..|
+00000330  18 f3 c2 b0 af d1 27 25  a9 ec ef 69 85 7a 72 c6  |......'%...i.zr.|
+00000340  b0 88 d2 c1 41 43 f4 69  62 25 13 eb f9 f8 16 03  |....AC.ib%......|
+00000350  03 00 2e 0d 00 00 26 03  01 02 40 00 1e 06 01 06  |......&...@.....|
+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 00 00 0e 00 00  |................|
+00000380  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|
 00000220  51 88 35 75 71 b5 e5 54  5b 12 2e 8f 09 67 fd a7  |Q.5uq..T[....g..|
 00000230  24 20 3e b2 56 1c ce 97  28 5e f8 2b 2d 4f 9e f1  |$ >.V...(^.+-O..|
 00000240  07 9f 6c 4b 5b 83 56 e2  32 42 e9 58 b6 d7 49 a6  |..lK[.V.2B.X..I.|
-00000250  b5 68 1a 41 03 56 6b dc  5a 89 16 03 03 00 92 0f  |.h.A.Vk.Z.......|
-00000260  00 00 8e 05 03 00 8a 30  81 87 02 42 00 cc a4 ad  |.......0...B....|
-00000270  0b ff 09 40 8f 2c a6 37  72 1d f7 d2 19 74 85 ad  |...@.,.7r....t..|
-00000280  ac 33 b0 b8 5b 56 39 cf  b0 ef 46 68 94 39 4c d0  |.3..[V9...Fh.9L.|
-00000290  f4 97 32 10 99 36 c5 95  c8 14 23 37 78 46 5c a9  |..2..6....#7xF\.|
-000002a0  20 95 65 47 ff 54 02 f1  aa 1d d7 bc 39 2d 02 41  | .eG.T......9-.A|
-000002b0  2e f9 d6 8c e8 c5 a9 6f  10 4f d6 5f 4e 88 e9 71  |.......o.O._N..q|
-000002c0  23 5b 6f b8 ab 19 d3 dd  ec f3 32 e3 3b fa 41 a2  |#[o.......2.;.A.|
-000002d0  e8 ae dc 27 8d 4e 79 f4  47 ef c9 8f bf 0b 41 3b  |...'.Ny.G.....A;|
-000002e0  94 16 cb 8f 1e b5 f3 4e  6e 42 46 35 1a 0c ca 79  |.......NnBF5...y|
-000002f0  4b 14 03 03 00 01 01 16  03 03 00 40 00 00 00 00  |K..........@....|
-00000300  00 00 00 00 00 00 00 00  00 00 00 00 64 1c d9 9f  |............d...|
-00000310  34 ec c2 74 76 7a 9f cf  95 19 be 8d 6a 2f 25 96  |4..tvz......j/%.|
-00000320  df de 18 ca 0e c9 d4 2f  e4 b0 34 10 5b 72 7a 18  |......./..4.[rz.|
-00000330  5c 64 d7 fc 2e 1b 28 10  ae a6 31 e9              |\d....(...1.|
+00000250  b5 68 1a 41 03 56 6b dc  5a 89 16 03 03 00 93 0f  |.h.A.Vk.Z.......|
+00000260  00 00 8f 05 03 00 8b 30  81 88 02 42 00 8a 82 c2  |.......0...B....|
+00000270  c0 30 8c a1 12 c4 4a ed  d1 00 3f 2d ee bd 8e 9c  |.0....J...?-....|
+00000280  a5 a0 d9 6f 44 27 49 60  e9 75 01 ee b4 0d 87 25  |...oD'I`.u.....%|
+00000290  2a 8d 67 f1 e3 d9 49 6f  a0 34 90 76 93 52 f9 17  |*.g...Io.4.v.R..|
+000002a0  fb 1b cc d0 5a f4 50 37  9c 4c 44 b6 61 5f 02 42  |....Z.P7.LD.a_.B|
+000002b0  01 ad 85 38 e9 3a 69 35  ea 74 76 2c 09 6b ab d4  |...8.:i5.tv,.k..|
+000002c0  e0 dc d1 d5 03 41 22 8e  8b 53 98 b7 f1 b6 e9 29  |.....A"..S.....)|
+000002d0  d2 57 34 dc e0 b6 71 77  79 bd 57 61 7c 30 77 00  |.W4...qwy.Wa|0w.|
+000002e0  7a 42 2d 1f ed e8 14 da  16 33 c6 31 e4 3d 53 3a  |zB-......3.1.=S:|
+000002f0  9a 37 14 03 03 00 01 01  16 03 03 00 40 00 00 00  |.7..........@...|
+00000300  00 00 00 00 00 00 00 00  00 00 00 00 00 d4 fe c1  |................|
+00000310  a6 fb 21 78 21 80 af 0d  da a1 80 68 e2 9c ec 0b  |..!x!......h....|
+00000320  57 8c 2a 7e f1 11 3b 52  ea 17 00 d1 d4 14 78 c5  |W.*~..;R......x.|
+00000330  81 39 12 ad 30 98 93 1b  29 77 45 7d 00           |.9..0...)wE}.|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 40 27 6f 24 a3 0c  |..........@'o$..|
-00000010  6d d7 68 4a fb 43 b0 97  02 6c 22 7e 2f a1 f1 7a  |m.hJ.C...l"~/..z|
-00000020  37 bf 38 82 dc a0 83 24  01 4b c0 4f 15 e1 7c 4c  |7.8....$.K.O..|L|
-00000030  d4 cd b8 e2 71 af f5 20  7d f9 4a 48 4b f0 a1 f3  |....q.. }.JHK...|
-00000040  7b 02 29 18 c0 87 a5 dd  c4 73 8e                 |{.)......s.|
+00000000  14 03 03 00 01 01 16 03  03 00 40 f7 0a 50 d0 87  |..........@..P..|
+00000010  fb f9 be b0 6b 8d 9b a5  8b d2 56 27 67 7d 3c 51  |....k.....V'g}<Q|
+00000020  af 53 8c 7d 61 9f 12 a5  54 5d ec 56 36 31 01 73  |.S.}a...T].V61.s|
+00000030  37 cb 5f ff 36 3c 1c 4a  e3 db ec 99 bc 86 15 e4  |7._.6<.J........|
+00000040  cd 5d 87 bd d7 80 c7 b1  fe 42 9f                 |.].......B.|
 >>> 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 bf 7a e1  23 0d d0 13 6e 96 81 6d  |......z.#...n..m|
-00000020  32 56 0f 75 7e 01 88 5f  6d e6 d6 ca ec 3c 17 e9  |2V.u~.._m....<..|
-00000030  44 a9 c0 1c a4 15 03 03  00 30 00 00 00 00 00 00  |D........0......|
-00000040  00 00 00 00 00 00 00 00  00 00 76 be 7a 77 29 01  |..........v.zw).|
-00000050  8e 13 02 66 81 43 a0 55  03 35 22 09 de ea 52 bb  |...f.C.U.5"...R.|
-00000060  51 cc c1 09 0e 9b 4d bd  94 85                    |Q.....M...|
+00000010  00 00 00 00 00 ef 81 cf  63 f1 b5 6b b2 30 6f 00  |........c..k.0o.|
+00000020  0e c0 0c 5d d4 85 76 d2  30 db 6b 14 06 e4 75 0b  |...]..v.0.k...u.|
+00000030  cf fc 72 aa 64 15 03 03  00 30 00 00 00 00 00 00  |..r.d....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 ef 28 8a e7 15 51  |...........(...Q|
+00000050  0d 0d 27 4f 36 35 f6 43  28 d2 16 dc a3 35 33 3e  |..'O65.C(....53>|
+00000060  be 80 db 31 a9 89 3d 17  c2 58                    |...1..=..X|
index 95c5782ab0d88deda7c7bd5380c5665d021e75d3..53f2f8645eeccb546c2af43c6279c4fb49c4515c 100644 (file)
@@ -1,67 +1,62 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 51 02 00 00  4d 03 03 79 e8 35 e3 d2  |....Q...M..y.5..|
-00000010  c0 5e 39 d1 46 da 9c 94  56 20 e2 06 d6 9b f6 dd  |.^9.F...V ......|
-00000020  4f 7a c1 e8 34 a1 9f 8b  c2 e1 fb 20 66 9c 5a 9a  |Oz..4...... f.Z.|
-00000030  3d 22 ab 8e d8 81 03 94  68 a0 6c 72 d8 23 0b 4b  |="......h.lr.#.K|
-00000040  fe 9d c7 49 a7 7c bd fa  b5 7a 5e 5b 00 05 00 00  |...I.|...z^[....|
-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..|
-00000080  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000090  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-000000a0  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-000000b0  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000c0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000d0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000e0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000f0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-00000100  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-00000110  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000120  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000130  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000140  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000150  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000160  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000170  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000180  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000190  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-000001a0  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-000001b0  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001c0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001d0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001e0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001f0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-00000200  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-00000210  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000220  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000230  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000240  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000250  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000260  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000270  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000280  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000290  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-000002a0  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-000002b0  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002c0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002d0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002e0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002f0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-00000300  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 2e 0d 00  |n8P)l...........|
-00000320  00 26 03 01 02 40 00 1e  06 01 06 02 06 03 05 01  |.&...@..........|
-00000330  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
-00000340  02 01 02 02 02 03 00 00  0e 00 00 00              |............|
+00000000  16 03 03 00 51 02 00 00  4d 03 03 e8 b5 19 bd df  |....Q...M.......|
+00000010  e5 18 78 4b 01 f1 3f 7f  ab 91 05 78 98 77 50 bf  |..xK..?....x.wP.|
+00000020  60 f5 a4 76 7b 3c 40 9f  54 56 68 20 a1 99 57 a7  |`..v{<@.TVh ..W.|
+00000030  a8 46 ca 26 22 d8 bb 8d  93 12 48 ff be 8e d3 d4  |.F.&".....H.....|
+00000040  e0 fd cd ce f5 d9 a9 2e  fe d4 cd 85 00 05 00 00  |................|
+00000050  05 ff 01 00 01 00 16 03  03 02 71 0b 00 02 6d 00  |..........q...m.|
+00000060  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000070  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000080  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000090  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+000000a0  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+000000b0  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000c0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000d0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000e0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000f0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+00000100  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+00000110  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000120  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000130  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000140  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000150  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000160  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000170  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000180  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000190  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+000001a0  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+000001b0  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001c0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001d0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001e0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001f0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+00000200  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+00000210  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f..@....xH.A0.|
+00000220  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000230  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000240  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000250  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H@.-.....|
+00000260  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000270  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000280  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000290  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+000002a0  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+000002b0  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002c0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
+000002d0  2e 0d 00 00 26 03 01 02  40 00 1e 06 01 06 02 06  |....&...@.......|
+000002e0  03 05 01 05 02 05 03 04  01 04 02 04 03 03 01 03  |................|
+000002f0  02 03 03 02 01 02 02 02  03 00 00 0e 00 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|
 000001e0  be e8 91 b3 da 1a f5 5d  a3 23 f5 26 8b 45 70 8d  |.......].#.&.Ep.|
 000001f0  65 62 9b 7e 01 99 3d 18  f6 10 9a 38 61 9b 2e 57  |eb.~..=....8a..W|
 00000200  e4 fa cc b1 8a ce e2 23  a0 87 f0 e1 67 51 eb 16  |.......#....gQ..|
-00000210  03 03 00 86 10 00 00 82  00 80 6d 51 f3 7f f9 3e  |..........mQ...>|
-00000220  fb 75 82 41 36 83 e8 6a  ee 2a 2e 25 90 67 4c 8e  |.u.A6..j.*.%.gL.|
-00000230  62 2f 30 81 17 e0 85 09  0c 2b b7 23 d7 b0 e2 1d  |b/0......+.#....|
-00000240  f7 3b d7 f5 a1 27 b6 ee  24 b6 1b cc 5b ea 66 0d  |.;...'..$...[.f.|
-00000250  6a f4 e5 85 f9 da 43 b4  0e 86 85 e1 f5 aa be c8  |j.....C.........|
-00000260  ce 39 4c 9c 86 00 08 c2  4b e2 c6 ec 2f f7 ce e6  |.9L.....K.../...|
-00000270  bd 77 82 6f 23 b6 e0 bd  a2 92 b7 3a ac e8 56 f1  |.w.o#......:..V.|
-00000280  af 54 5e 46 87 e9 3b 33  e7 b8 28 b7 d6 c8 90 35  |.T^F..;3..(....5|
-00000290  d4 1c 43 d1 30 6f 55 4e  0a 70 16 03 03 00 92 0f  |..C.0oUN.p......|
-000002a0  00 00 8e 05 03 00 8a 30  81 87 02 41 19 c7 50 06  |.......0...A..P.|
-000002b0  42 82 f9 e5 ec 0b f7 65  7e b1 19 53 5f 23 ab 19  |B......e~..S_#..|
-000002c0  54 08 ec d2 a7 22 dd 83  7c 97 76 59 a5 6b f4 1d  |T...."..|.vY.k..|
-000002d0  92 86 34 2d ce 71 bb 01  d2 8a 67 0e a8 fb 51 e4  |..4-.q....g...Q.|
-000002e0  69 9c 27 23 74 b9 fd 6f  b6 5e 48 a0 cc 02 42 01  |i.'#t..o.^H...B.|
-000002f0  50 97 b7 95 14 f4 a6 f2  95 63 17 38 59 a1 51 95  |P........c.8Y.Q.|
-00000300  1e bc 99 fb fd 82 8b ab  cb 4d 8e 17 a9 f8 e9 c2  |.........M......|
-00000310  9b 93 15 02 50 e6 c2 05  54 e7 8a ec 6f 93 1f 79  |....P...T...o..y|
-00000320  8d 67 e7 2d d6 65 ab 97  fd be 20 97 bd 6b c4 fc  |.g.-.e.... ..k..|
-00000330  02 14 03 03 00 01 01 16  03 03 00 24 24 df 52 6e  |...........$$.Rn|
-00000340  c1 35 48 fe 60 77 28 69  36 fe 96 a1 72 db a2 f5  |.5H.`w(i6...r...|
-00000350  d0 b7 c3 d9 67 e5 ee f2  d9 18 bf f0 35 80 06 c2  |....g.......5...|
+00000210  03 03 00 86 10 00 00 82  00 80 73 bd 73 65 92 86  |..........s.se..|
+00000220  23 41 14 79 7f d5 c1 10  ce 94 4d ad 9c c3 a9 87  |#A.y......M.....|
+00000230  b5 32 52 f8 6b 11 93 2d  9b 98 0b 8b 1d c0 f6 53  |.2R.k..-.......S|
+00000240  17 6d c7 9c 2e ae c9 6f  cc 99 23 38 37 1a 10 fe  |.m.....o..#87...|
+00000250  05 0b b5 55 0a 14 e9 60  7d 70 26 98 e2 54 d9 65  |...U...`}p&..T.e|
+00000260  cf 2e f4 53 5f 1d aa 3a  f6 33 7b eb 4c 0e b3 ff  |...S_..:.3{.L...|
+00000270  5a db 36 2a 47 f3 df f9  fc f5 31 78 83 aa 6b 52  |Z.6*G.....1x..kR|
+00000280  b7 ba 1a 96 bc fa c1 a1  a9 bb 2b f5 38 89 00 4d  |..........+.8..M|
+00000290  e5 78 13 4e a4 38 46 42  dc 16 16 03 03 00 92 0f  |.x.N.8FB........|
+000002a0  00 00 8e 05 03 00 8a 30  81 87 02 42 01 4c f6 31  |.......0...B.L.1|
+000002b0  4f ec 64 bb ce d0 96 4d  66 f3 8d 64 78 c9 2d 47  |O.d....Mf..dx.-G|
+000002c0  39 02 88 31 49 84 7f cc  a8 af c1 17 35 fb 46 b1  |9..1I.......5.F.|
+000002d0  dc 07 58 71 13 6b 8e 71  2b 94 fd 41 7c 26 45 39  |..Xq.k.q+..A|&E9|
+000002e0  28 b1 aa f7 5b 89 04 de  84 d1 b5 d9 9f f3 02 41  |(...[..........A|
+000002f0  4e f6 2a ed 39 ee 63 68  da f5 ae 1b 4d f5 01 0f  |N.*.9.ch....M...|
+00000300  bc f7 05 d2 96 42 67 e3  8f ff 27 d5 bf c4 53 bf  |.....Bg...'...S.|
+00000310  8a d7 46 58 05 54 94 d8  73 a9 d9 38 40 5f cb 8c  |..FX.T..s..8@_..|
+00000320  c7 d1 94 56 2a e1 61 32  29 f7 c9 c1 e8 95 30 e3  |...V*.a2).....0.|
+00000330  33 14 03 03 00 01 01 16  03 03 00 24 b1 86 d2 50  |3..........$...P|
+00000340  fc ea 68 b1 d9 3d b7 2c  fd 2c 87 f0 d4 44 2b 22  |..h..=.,.,...D+"|
+00000350  b8 47 74 77 46 14 6d 18  b3 08 9c 3a d4 a1 ba cb  |.GtwF.m....:....|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 40 5b dc 01 59  |..........$@[..Y|
-00000010  33 6e 61 5a 6d fc c8 a5  f5 00 9b 55 77 c5 e6 f2  |3naZm......Uw...|
-00000020  c6 5c b6 2f 94 3c 72 5b  b5 0c 3e 78 88 e6 44     |.\./.<r[..>x..D|
+00000000  14 03 03 00 01 01 16 03  03 00 24 70 c7 ee d4 d3  |..........$p....|
+00000010  d3 ad dc 5a d1 a3 01 89  4d ae 0f b9 7b 97 91 4a  |...Z....M...{..J|
+00000020  c0 5b e2 94 ef 5f 2f e0  90 1a 18 8a e8 50 9d     |.[..._/......P.|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1a cd 2f 11  b1 3a e4 1c 31 95 9b c4  |....../..:..1...|
-00000010  37 20 9f 03 d3 45 a4 15  e1 09 1e 0c f6 5d d3 15  |7 ...E.......]..|
-00000020  03 03 00 16 d7 f6 a1 d0  ad 41 69 73 c0 40 22 f2  |.........Ais.@".|
-00000030  5f e8 c3 50 f9 35 fc 59  e0 3a                    |_..P.5.Y.:|
+00000000  17 03 03 00 1a e8 e8 00  30 71 09 61 65 55 90 c8  |........0q.aeU..|
+00000010  d6 fd 8d 5d a9 fb e6 2b  d4 45 a9 8c ea 2f 0b 15  |...]...+.E.../..|
+00000020  03 03 00 16 f2 d3 36 ce  26 42 59 1b d7 15 c5 c4  |......6.&BY.....|
+00000030  8b 0b 06 0a d0 fd 78 62  3d 39                    |......xb=9|
index 52e3befe615cd2c972848b84276ace73c97b5514..9ba51f5ac62a6ea9f9972e129cb7316b12cb5750 100644 (file)
@@ -1,81 +1,76 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 74 fe 19 af 4b  |....Y...U..t...K|
-00000010  f3 d8 92 62 5a df 90 2c  cc 09 fd 79 45 26 cd 52  |...bZ..,...yE&.R|
-00000020  9a e6 da 16 99 fe 1d 91  79 a7 a0 20 b3 13 e9 03  |........y.. ....|
-00000030  52 23 5f f0 55 59 f1 9e  00 a7 77 97 90 ed 2b fb  |R#_.UY....w...+.|
-00000040  9c ab fe b1 db ea 16 95  95 68 b0 e9 c0 30 00 00  |.........h...0..|
+00000000  16 03 03 00 59 02 00 00  55 03 03 f5 6d a6 9a 3d  |....Y...U...m..=|
+00000010  b4 32 c7 59 b9 f7 09 bb  56 7e 06 26 02 ac eb dd  |.2.Y....V~.&....|
+00000020  78 91 e4 cd f9 f4 e7 98  7f 13 f0 20 6d d5 42 4a  |x.......... m.BJ|
+00000030  85 ac 86 9a a6 78 6d 5c  d7 ef 9d 16 dc ff 5a 41  |.....xm\......ZA|
+00000040  91 5a 54 ff ba f6 90 f4  2a 4f fd 37 c0 30 00 00  |.ZT.....*O.7.0..|
 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..............|
-00000080  a4 8a 7f b8 ca 30 0d 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
-00000090  01 05 05 00 30 45 31 0b  30 09 06 03 55 04 06 13  |....0E1.0...U...|
-000000a0  02 41 55 31 13 30 11 06  03 55 04 08 13 0a 53 6f  |.AU1.0...U....So|
-000000b0  6d 65 2d 53 74 61 74 65  31 21 30 1f 06 03 55 04  |me-State1!0...U.|
-000000c0  0a 13 18 49 6e 74 65 72  6e 65 74 20 57 69 64 67  |...Internet Widg|
-000000d0  69 74 73 20 50 74 79 20  4c 74 64 30 1e 17 0d 31  |its Pty Ltd0...1|
-000000e0  30 30 34 32 34 30 39 30  39 33 38 5a 17 0d 31 31  |00424090938Z..11|
-000000f0  30 34 32 34 30 39 30 39  33 38 5a 30 45 31 0b 30  |0424090938Z0E1.0|
-00000100  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
-00000110  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
-00000120  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
-00000130  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
-00000140  74 64 30 81 9f 30 0d 06  09 2a 86 48 86 f7 0d 01  |td0..0...*.H....|
-00000150  01 01 05 00 03 81 8d 00  30 81 89 02 81 81 00 bb  |........0.......|
-00000160  79 d6 f5 17 b5 e5 bf 46  10 d0 dc 69 be e6 2b 07  |y......F...i..+.|
-00000170  43 5a d0 03 2d 8a 7a 43  85 b7 14 52 e7 a5 65 4c  |CZ..-.zC...R..eL|
-00000180  2c 78 b8 23 8c b5 b4 82  e5 de 1f 95 3b 7e 62 a5  |,x.#........;~b.|
-00000190  2c a5 33 d6 fe 12 5c 7a  56 fc f5 06 bf fa 58 7b  |,.3...\zV.....X{|
-000001a0  26 3f b5 cd 04 d3 d0 c9  21 96 4a c7 f4 54 9f 5a  |&?......!.J..T.Z|
-000001b0  bf ef 42 71 00 fe 18 99  07 7f 7e 88 7d 7d f1 04  |..Bq......~.}}..|
-000001c0  39 c4 a2 2e db 51 c9 7c  e3 c0 4c 3b 32 66 01 cf  |9....Q.|..L;2f..|
-000001d0  af b1 1d b8 71 9a 1d db  db 89 6b ae da 2d 79 02  |....q.....k..-y.|
-000001e0  03 01 00 01 a3 81 a7 30  81 a4 30 1d 06 03 55 1d  |.......0..0...U.|
-000001f0  0e 04 16 04 14 b1 ad e2  85 5a cf cb 28 db 69 ce  |.........Z..(.i.|
-00000200  23 69 de d3 26 8e 18 88  39 30 75 06 03 55 1d 23  |#i..&...90u..U.#|
-00000210  04 6e 30 6c 80 14 b1 ad  e2 85 5a cf cb 28 db 69  |.n0l......Z..(.i|
-00000220  ce 23 69 de d3 26 8e 18  88 39 a1 49 a4 47 30 45  |.#i..&...9.I.G0E|
-00000230  31 0b 30 09 06 03 55 04  06 13 02 41 55 31 13 30  |1.0...U....AU1.0|
-00000240  11 06 03 55 04 08 13 0a  53 6f 6d 65 2d 53 74 61  |...U....Some-Sta|
-00000250  74 65 31 21 30 1f 06 03  55 04 0a 13 18 49 6e 74  |te1!0...U....Int|
-00000260  65 72 6e 65 74 20 57 69  64 67 69 74 73 20 50 74  |ernet Widgits Pt|
-00000270  79 20 4c 74 64 82 09 00  85 b0 bb a4 8a 7f b8 ca  |y Ltd...........|
-00000280  30 0c 06 03 55 1d 13 04  05 30 03 01 01 ff 30 0d  |0...U....0....0.|
-00000290  06 09 2a 86 48 86 f7 0d  01 01 05 05 00 03 81 81  |..*.H...........|
-000002a0  00 08 6c 45 24 c7 6b b1  59 ab 0c 52 cc f2 b0 14  |..lE$.k.Y..R....|
-000002b0  d7 87 9d 7a 64 75 b5 5a  95 66 e4 c5 2b 8e ae 12  |...zdu.Z.f..+...|
-000002c0  66 1f eb 4f 38 b3 6e 60  d3 92 fd f7 41 08 b5 25  |f..O8.n`....A..%|
-000002d0  13 b1 18 7a 24 fb 30 1d  ba ed 98 b9 17 ec e7 d7  |...z$.0.........|
-000002e0  31 59 db 95 d3 1d 78 ea  50 56 5c d5 82 5a 2d 5a  |1Y....x.PV\..Z-Z|
-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 22  |.............A."|
-00000330  84 e9 5e 6e 35 92 a3 83  73 0a d6 0d 1a c1 4d ab  |..^n5...s.....M.|
-00000340  1f ab c2 dc 3f 53 a5 7d  38 c0 92 a4 82 e1 3c c5  |....?S.}8.....<.|
-00000350  24 60 20 a5 3b c5 65 ba  9c f1 b9 a5 b9 c2 70 73  |$` .;.e.......ps|
-00000360  19 74 a6 d1 0f 75 b4 75  e0 e8 60 20 e9 23 fe 04  |.t...u.u..` .#..|
-00000370  01 00 80 92 e0 56 3f 48  0d 10 23 48 b5 95 b6 91  |.....V?H..#H....|
-00000380  3e 8a 2e c7 02 e2 85 0e  59 c8 03 24 d9 1a 1a 25  |>.......Y..$...%|
-00000390  8e 12 bb 0b 83 ac 51 36  81 3f bc 0e be b9 3b 1d  |......Q6.?....;.|
-000003a0  67 56 21 4d 24 36 84 05  61 e7 70 60 d5 8e ae 97  |gV!M$6..a.p`....|
-000003b0  b8 3a d3 b1 94 72 52 cd  b0 0d dd 46 b1 15 3b 58  |.:...rR....F..;X|
-000003c0  c1 a4 63 2c 4c 31 f9 c7  4f 27 c1 0f f0 24 36 72  |..c,L1..O'...$6r|
-000003d0  e0 f8 51 12 86 c2 13 ed  6b 84 a8 15 c3 d0 39 55  |..Q.....k.....9U|
-000003e0  a4 60 50 88 c9 1e 60 60  aa 8d a5 31 3e 35 c3 f8  |.`P...``...1>5..|
-000003f0  2c 90 1c 16 03 03 00 2e  0d 00 00 26 03 01 02 40  |,..........&...@|
-00000400  00 1e 06 01 06 02 06 03  05 01 05 02 05 03 04 01  |................|
-00000410  04 02 04 03 03 01 03 02  03 03 02 01 02 02 02 03  |................|
-00000420  00 00 0e 00 00 00                                 |......|
+00000060  03 02 71 0b 00 02 6d 00  02 6a 00 02 67 30 82 02  |..q...m..j..g0..|
+00000070  63 30 82 01 cc a0 03 02  01 02 02 09 00 a2 73 00  |c0............s.|
+00000080  0c 81 00 cb f3 30 0d 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
+00000090  01 0b 05 00 30 2b 31 17  30 15 06 03 55 04 0a 13  |....0+1.0...U...|
+000000a0  0e 47 6f 6f 67 6c 65 20  54 45 53 54 49 4e 47 31  |.Google TESTING1|
+000000b0  10 30 0e 06 03 55 04 03  13 07 47 6f 20 52 6f 6f  |.0...U....Go Roo|
+000000c0  74 30 1e 17 0d 31 35 30  31 30 31 30 30 30 30 30  |t0...15010100000|
+000000d0  30 5a 17 0d 32 35 30 31  30 31 30 30 30 30 30 30  |0Z..250101000000|
+000000e0  5a 30 26 31 17 30 15 06  03 55 04 0a 13 0e 47 6f  |Z0&1.0...U....Go|
+000000f0  6f 67 6c 65 20 54 45 53  54 49 4e 47 31 0b 30 09  |ogle TESTING1.0.|
+00000100  06 03 55 04 03 13 02 47  6f 30 81 9f 30 0d 06 09  |..U....Go0..0...|
+00000110  2a 86 48 86 f7 0d 01 01  01 05 00 03 81 8d 00 30  |*.H............0|
+00000120  81 89 02 81 81 00 af 87  88 f6 20 1b 95 65 6c 14  |.......... ..el.|
+00000130  ab 44 05 af 3b 45 14 e3  b7 6d fd 00 63 4d 95 7f  |.D..;E...m..cM..|
+00000140  fe 6a 62 35 86 c0 4a f9  18 7c f6 aa 25 5e 7a 64  |.jb5..J..|..%^zd|
+00000150  31 66 00 ba f4 8e 92 af  c7 6b d8 76 d4 f3 5f 41  |1f.......k.v.._A|
+00000160  cb 6e 56 15 97 1b 97 c1  3c 12 39 21 66 3d 2b 16  |.nV.....<.9!f=+.|
+00000170  d1 bc db 1c c0 a7 da b7  ca ad ba da cb d5 21 50  |..............!P|
+00000180  ec de 8d ab d1 6b 81 4b  89 02 f3 c4 be c1 6c 89  |.....k.K......l.|
+00000190  b1 44 84 bd 21 d1 04 7d  9d 16 4d f9 82 15 f6 ef  |.D..!..}..M.....|
+000001a0  fa d6 09 47 f2 fb 02 03  01 00 01 a3 81 93 30 81  |...G..........0.|
+000001b0  90 30 0e 06 03 55 1d 0f  01 01 ff 04 04 03 02 05  |.0...U..........|
+000001c0  a0 30 1d 06 03 55 1d 25  04 16 30 14 06 08 2b 06  |.0...U.%..0...+.|
+000001d0  01 05 05 07 03 01 06 08  2b 06 01 05 05 07 03 02  |........+.......|
+000001e0  30 0c 06 03 55 1d 13 01  01 ff 04 02 30 00 30 19  |0...U.......0.0.|
+000001f0  06 03 55 1d 0e 04 12 04  10 12 50 8d 89 6f 1b d1  |..U.......P..o..|
+00000200  dc 54 4d 6e cb 69 5e 06  f4 30 1b 06 03 55 1d 23  |.TMn.i^..0...U.#|
+00000210  04 14 30 12 80 10 bf 3d  b6 a9 66 f2 b8 40 cf ea  |..0....=..f..@..|
+00000220  b4 03 78 48 1a 41 30 19  06 03 55 1d 11 04 12 30  |..xH.A0...U....0|
+00000230  10 82 0e 65 78 61 6d 70  6c 65 2e 67 6f 6c 61 6e  |...example.golan|
+00000240  67 30 0d 06 09 2a 86 48  86 f7 0d 01 01 0b 05 00  |g0...*.H........|
+00000250  03 81 81 00 92 7c af 91  55 12 18 96 59 31 a6 48  |.....|..U...Y1.H|
+00000260  40 d5 2d d5 ee bb 02 a0  f5 c2 1e 7c 9b b3 30 7d  |@.-........|..0}|
+00000270  3c dc 76 da 4f 3d c0 fa  ae 2d 33 24 6b 03 7b 1b  |<.v.O=...-3$k.{.|
+00000280  67 59 11 21 b5 11 bc 77  b9 d9 e0 6e a8 2d 2e 35  |gY.!...w...n.-.5|
+00000290  fa 64 5f 22 3e 63 10 6b  be ff 14 86 6d 0d f0 15  |.d_">c.k....m...|
+000002a0  31 a8 14 38 1e 3b 84 87  2c cb 98 ed 51 76 b9 b1  |1..8.;..,...Qv..|
+000002b0  4f dd db 9b 84 04 86 40  fa 51 dd ba b4 8d eb e3  |O......@.Q......|
+000002c0  46 de 46 b9 4f 86 c7 f9  a4 c2 41 34 ac cc f6 ea  |F.F.O.....A4....|
+000002d0  b0 ab 39 18 16 03 03 00  cd 0c 00 00 c9 03 00 17  |..9.............|
+000002e0  41 04 2a 2a b7 63 a8 8e  34 67 32 18 57 6e fe 2a  |A.**.c..4g2.Wn.*|
+000002f0  51 41 41 5f 65 a3 a7 e9  d6 0b 42 7f 77 fb 40 09  |QAA_e.....B.w.@.|
+00000300  c8 7a a2 9b fd 5f 6e 2b  ce 85 f6 24 c2 8d e8 bb  |.z..._n+...$....|
+00000310  69 3e dc 51 15 6f a8 db  a4 fb 11 10 70 04 82 6a  |i>.Q.o......p..j|
+00000320  7b 81 04 01 00 80 7a a3  c9 1b e6 02 33 39 55 36  |{.....z.....39U6|
+00000330  dc f9 2d f7 00 5b 8d f4  de 7a f7 3b 1b 4c 9a 27  |..-..[...z.;.L.'|
+00000340  f6 db 3c d1 6b f8 d6 7a  20 53 33 5f 88 9f f6 73  |..<.k..z S3_...s|
+00000350  90 2f 35 9e f6 05 b5 80  96 4f c8 85 e6 72 95 ba  |./5......O...r..|
+00000360  3b 42 43 94 c3 0b db 91  ff 6b 24 c6 b1 78 de 18  |;BC......k$..x..|
+00000370  9f d5 3b 33 53 22 45 bf  cb b2 d2 77 ce 03 56 7b  |..;3S"E....w..V{|
+00000380  b7 56 b6 ec 04 64 62 04  f7 f8 52 1a 47 49 01 71  |.V...db...R.GI.q|
+00000390  29 9e ee 68 1f e9 c6 36  fb 77 4c 9a 14 90 e1 70  |)..h...6.wL....p|
+000003a0  7d 7e 77 92 a6 18 16 03  03 00 2e 0d 00 00 26 03  |}~w...........&.|
+000003b0  01 02 40 00 1e 06 01 06  02 06 03 05 01 05 02 05  |..@.............|
+000003c0  03 04 01 04 02 04 03 03  01 03 02 03 03 02 01 02  |................|
+000003d0  02 02 03 00 00 0e 00 00  00                       |.........|
 >>> Flow 3 (client to server)
 00000000  16 03 03 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|
 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 05 01 00 80  33 bb 8e 67 64 03 e7 7e  |........3..gd..~|
-00000260  be a5 b1 bc cf 7a 07 24  01 17 c3 3d 4b 72 dd c3  |.....z.$...=Kr..|
-00000270  64 a7 36 e8 49 ab b6 87  ce d6 af 9e 07 22 76 e8  |d.6.I........"v.|
-00000280  0d 44 a3 36 c9 eb a4 49  85 cf 72 67 e8 2a a7 5b  |.D.6...I..rg.*.[|
-00000290  d3 f2 46 af 53 48 c6 13  f7 0b 5b 9c c7 4d 3e 05  |..F.SH....[..M>.|
-000002a0  3c 0f 69 a7 40 3a e8 70  04 01 1c 29 b2 42 0f 5f  |<.i.@:.p...).B._|
-000002b0  1c d5 b7 5c c2 17 07 7f  bd a2 b3 9a 95 81 51 24  |...\..........Q$|
-000002c0  54 5c 42 d6 a4 76 c0 d7  54 d2 11 54 bf fd dc a0  |T\B..v..T..T....|
-000002d0  ee 95 26 64 59 a0 fc 51  14 03 03 00 01 01 16 03  |..&dY..Q........|
-000002e0  03 00 28 00 00 00 00 00  00 00 00 af f4 8a be d9  |..(.............|
-000002f0  ff f1 44 e4 41 ab 9b b3  d8 b0 3d 3f 6b c5 1d b6  |..D.A.....=?k...|
-00000300  1d 9e 35 f5 20 f4 2a af  e8 35 77                 |..5. .*..5w|
+00000250  0f 00 00 84 05 01 00 80  45 11 dc 3c 2a fc 5f aa  |........E..<*._.|
+00000260  60 09 59 47 45 cc a7 74  e3 9d 0c c3 a4 08 b0 2a  |`.YGE..t.......*|
+00000270  44 47 cd 66 ed 94 54 8f  d7 74 fd 47 a3 90 56 69  |DG.f..T..t.G..Vi|
+00000280  5a b6 c5 b0 bd c2 16 a2  1e af 58 37 88 cb d1 4b  |Z.........X7...K|
+00000290  5c ee e6 0f 16 9b e0 d7  43 b3 e6 0a b2 90 fa 21  |\.......C......!|
+000002a0  78 95 3e 7f fc c1 b3 df  a1 bf fc eb bc e8 37 63  |x.>...........7c|
+000002b0  87 33 3e c3 9a e4 6c 0f  3d 0d 9f e8 db 2d 82 ad  |.3>...l.=....-..|
+000002c0  3c 6d f7 4a 5e 81 21 4f  19 0e 60 2d ef c1 40 8d  |<m.J^.!O..`-..@.|
+000002d0  cb 97 4f 08 1c c0 66 e7  14 03 03 00 01 01 16 03  |..O...f.........|
+000002e0  03 00 28 00 00 00 00 00  00 00 00 8c ce 5e 94 90  |..(..........^..|
+000002f0  22 2c 8d 64 be 29 99 62  1f 95 6e 3b 51 22 9c eb  |",.d.).b..n;Q"..|
+00000300  f3 0f 24 b8 a5 84 58 70  82 71 a1                 |..$...Xp.q.|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 ff 0d 47 63 2b  |..........(..Gc+|
-00000010  bd 00 3a ad 82 e3 a7 b3  b0 84 4a 26 f4 30 78 20  |..:.......J&.0x |
-00000020  80 f2 2b 15 98 61 1c cb  8b 17 67 8a 11 96 aa 93  |..+..a....g.....|
-00000030  68 f7 fb                                          |h..|
+00000000  14 03 03 00 01 01 16 03  03 00 28 b1 23 11 48 69  |..........(.#.Hi|
+00000010  52 44 34 f1 9a 69 2b 79  fb 68 b4 53 d5 d7 08 08  |RD4..i+y.h.S....|
+00000020  34 95 5f 56 b2 57 eb 91  31 6c 32 25 b5 68 8a 8e  |4._V.W..1l2%.h..|
+00000030  f1 68 6e                                          |.hn|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 a6 8d 7b  |...............{|
-00000010  99 5e a2 e1 95 bb 5f e4  01 f4 0e 20 52 b4 64 4e  |.^...._.... R.dN|
-00000020  86 b1 3f 15 03 03 00 1a  00 00 00 00 00 00 00 02  |..?.............|
-00000030  61 98 eb d0 7c ac bd 00  ac 7a e1 32 20 3e 81 b6  |a...|....z.2 >..|
-00000040  9d d5                                             |..|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 03 ab 9e  |................|
+00000010  f0 a6 6c f1 ea 23 20 63  42 a3 9d c6 5d 41 96 c1  |..l..# cB...]A..|
+00000020  44 b2 8b 15 03 03 00 1a  00 00 00 00 00 00 00 02  |D...............|
+00000030  e9 73 41 50 28 b0 d3 00  46 81 d6 c9 1a ca ab cd  |.sAP(...F.......|
+00000040  44 9b                                             |D.|
index 23bf29d776e1b441673c6e30c982dc627b94d4e3..4fa5e20e93a5e8c091fd712ac75113e48d64386a 100644 (file)
@@ -1,19 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 b3 7f 4e e7 11  |....Y...U....N..|
-00000010  6d bc 56 ec 9c a8 61 08  d6 5a 2a 42 7b f1 94 0a  |m.V...a..Z*B{...|
-00000020  29 35 8b 7e 23 a0 6c 59  23 cf 39 20 84 09 b6 5b  |)5.~#.lY#.9 ...[|
-00000030  2f 46 80 3b 26 92 fd 81  e9 24 8c e2 b8 64 a2 03  |/F.;&....$...d..|
-00000040  3a 68 c3 7b 44 f8 28 41  e2 d3 6c 7c c0 09 00 00  |:h.{D.(A..l|....|
+00000000  16 03 03 00 59 02 00 00  55 03 03 2a 01 f8 3e d1  |....Y...U..*..>.|
+00000010  52 41 2e 9a 8d 56 ff 52  3d 6a fe 65 ab 91 bb b7  |RA...V.R=j.e....|
+00000020  82 be f1 60 40 3b 80 a1  f8 dc 95 20 48 87 41 46  |...`@;..... H.AF|
+00000030  6a d2 f3 b8 d8 68 20 40  45 b7 fe 19 21 bc 84 00  |j....h @E...!...|
+00000040  5d 40 40 21 58 3e 7d fb  a7 e3 30 37 c0 09 00 00  |]@@!X>}...07....|
 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....|
 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 d7 0c 00  00 d3 03 00 17 41 04 0f  |*............A..|
-00000280  4d b0 41 d4 dc 6b 8a 85  52 eb eb 18 4a 8f a7 e6  |M.A..k..R...J...|
-00000290  24 52 e5 86 be 57 d7 0a  e7 23 84 a8 a9 6c 96 08  |$R...W...#...l..|
-000002a0  4b f7 47 32 79 d9 df 81  f6 05 40 63 3b 14 67 3b  |K.G2y.....@c;.g;|
-000002b0  ea 01 a0 0d 43 1a 36 29  b3 51 7a e4 af 1b 67 04  |....C.6).Qz...g.|
-000002c0  03 00 8a 30 81 87 02 42  01 8e 57 8a b8 b7 5b 2f  |...0...B..W...[/|
-000002d0  9c 31 74 d8 7d 68 d7 6e  83 73 5f fb d0 cd de 66  |.1t.}h.n.s_....f|
-000002e0  60 fa 0a 0a 15 0b 30 3b  08 b6 f1 3e 4f 20 13 62  |`.....0;...>O .b|
-000002f0  b5 ff 86 81 dc 42 a1 4c  af c8 ff b3 24 81 d8 e1  |.....B.L....$...|
-00000300  d1 09 0c 32 11 92 5e dd  3f 87 02 41 76 a7 29 48  |...2..^.?..Av.)H|
-00000310  52 68 1c 72 4d d5 39 bf  fa 61 ec b2 27 ce 10 4e  |Rh.rM.9..a..'..N|
-00000320  86 12 3d 1e 04 9c 11 b7  b4 0c cf 98 9d 01 c3 93  |..=.............|
-00000330  cf 83 9e 92 9a ca fd 8f  b1 9f 1b 20 c4 fb a4 46  |........... ...F|
-00000340  60 fc fd d5 33 b0 8f b5  b5 c8 a4 70 c5 16 03 03  |`...3......p....|
-00000350  00 2e 0d 00 00 26 03 01  02 40 00 1e 06 01 06 02  |.....&...@......|
-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 00 00 0e 00 00 00  |................|
+00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 00  |*............A..|
+00000280  9e 90 3a 3d 00 37 0a c0  43 92 6e bf b4 23 d9 64  |..:=.7..C.n..#.d|
+00000290  99 d2 90 9e eb 88 b6 d6  6f 15 4a 22 72 f0 bf 5e  |........o.J"r..^|
+000002a0  72 80 93 90 aa f1 d1 9c  45 c6 6e 3a f8 a9 6f fe  |r.......E.n:..o.|
+000002b0  fb 24 dc b1 4d 52 39 91  f5 48 36 06 f6 15 0e 04  |.$..MR9..H6.....|
+000002c0  03 00 8b 30 81 88 02 42  00 a9 54 74 a7 a8 d0 04  |...0...B..Tt....|
+000002d0  ae ef e4 64 38 74 21 e6  18 f0 79 b2 d7 7e 7b 0e  |...d8t!...y..~{.|
+000002e0  f6 74 75 52 f0 b8 15 3c  3d 15 52 75 9f 60 03 63  |.tuR...<=.Ru.`.c|
+000002f0  15 b8 1e b8 0e 5c 58 c7  e7 2f 6d 76 c7 c8 42 7a  |.....\X../mv..Bz|
+00000300  df 15 26 4b dc 9c 3b 4d  b3 b6 02 42 00 a5 fd bf  |..&K..;M...B....|
+00000310  a9 5d fc 87 42 24 f9 0b  7a 17 97 7c ee 45 1c 29  |.]..B$..z..|.E.)|
+00000320  3a 07 5f df 4d f2 d3 cb  fc a6 fd 84 34 2c 40 84  |:._.M.......4,@.|
+00000330  06 76 bf 43 35 d2 f6 9a  7c d6 1b 5e d8 fd 08 35  |.v.C5...|..^...5|
+00000340  1b 90 0e 24 a7 48 9d 71  ab 4a 11 92 d3 6e 16 03  |...$.H.q.J...n..|
+00000350  03 00 2e 0d 00 00 26 03  01 02 40 00 1e 06 01 06  |......&...@.....|
+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 00 00 0e 00 00  |................|
+00000380  00                                                |.|
 >>> Flow 3 (client to server)
 00000000  16 03 03 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|
 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 05 01 00 80  02 19 16 cc 97 ad 70 20  |..............p |
-00000260  bd 64 63 dd b6 81 a0 16  b3 46 4b 42 ff 21 58 2c  |.dc......FKB.!X,|
-00000270  bb 2b 4c e1 4e d7 49 4d  5c 7c 63 32 3e ef e6 ad  |.+L.N.IM\|c2>...|
-00000280  85 3f ab b4 5c 2a 37 76  8b 28 56 08 4f 08 b9 51  |.?..\*7v.(V.O..Q|
-00000290  71 14 07 27 47 45 11 a0  03 cf 72 7d 67 ef 31 8d  |q..'GE....r}g.1.|
-000002a0  e7 db 36 76 b1 b3 f4 bf  aa 6c c4 56 94 35 71 e1  |..6v.....l.V.5q.|
-000002b0  dd 88 6d 15 90 c8 70 ad  d8 95 55 42 9b c1 45 19  |..m...p...UB..E.|
-000002c0  36 ce 87 c6 fd 94 8a d4  98 6e ec 18 d5 da 59 54  |6........n....YT|
-000002d0  80 a7 8c 90 ae 55 20 1c  14 03 03 00 01 01 16 03  |.....U .........|
+00000250  0f 00 00 84 05 01 00 80  20 ef 4b 1c d7 67 37 6e  |........ .K..g7n|
+00000260  24 12 9e e9 59 b1 6d da  e5 3e 6b 11 03 f4 96 e4  |$...Y.m..>k.....|
+00000270  2e fb 03 e1 13 af 73 4d  15 11 c1 80 e2 ed 11 c6  |......sM........|
+00000280  73 6a 96 ce d1 26 e4 bc  fe 71 c9 48 32 fd d8 70  |sj...&...q.H2..p|
+00000290  01 9d 18 7b ed a3 bd 6a  68 df 45 a0 d5 77 79 d2  |...{...jh.E..wy.|
+000002a0  5b e2 8c 96 68 95 46 8d  7d e6 b6 26 fa e1 c4 05  |[...h.F.}..&....|
+000002b0  4c d1 39 4e 35 e3 0c 1b  26 37 2e 0b 9b 0b cf f7  |L.9N5...&7......|
+000002c0  25 c3 da 27 18 70 83 18  49 ff ee ba e3 f8 70 75  |%..'.p..I.....pu|
+000002d0  e8 9b 2d 89 d7 b2 00 a5  14 03 03 00 01 01 16 03  |..-.............|
 000002e0  03 00 40 00 00 00 00 00  00 00 00 00 00 00 00 00  |..@.............|
-000002f0  00 00 00 58 fe bc 5c ba  b2 a9 96 77 2f 95 c9 10  |...X..\....w/...|
-00000300  fd 6d fc 6a 88 8c df 82  c3 a4 3d cc 28 f4 bf 7d  |.m.j......=.(..}|
-00000310  4a f8 3d 97 36 e5 a0 76  92 94 da dd cc f5 e4 0e  |J.=.6..v........|
-00000320  7a c4 2c                                          |z.,|
+000002f0  00 00 00 d3 33 79 85 64  14 07 a6 93 74 f8 f8 55  |....3y.d....t..U|
+00000300  0f fb fc 8e 1b 4c 38 21  b6 61 c5 4b b2 d4 17 b2  |.....L8!.a.K....|
+00000310  c4 be a6 4b d6 3f a3 5f  3c ff 5f 1d 93 a2 c4 82  |...K.?._<._.....|
+00000320  96 90 eb                                          |...|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 40 81 ab 5a 66 a8  |..........@..Zf.|
-00000010  0f a5 d3 07 00 66 45 1f  31 a9 ef f7 a0 d9 23 46  |.....fE.1.....#F|
-00000020  f0 3e 50 18 99 e3 5a bd  eb b7 1d 81 d5 95 d5 ee  |.>P...Z.........|
-00000030  21 31 41 4b 19 92 b5 95  36 da 21 c0 4a 2a a0 1c  |!1AK....6.!.J*..|
-00000040  a3 9f 8e a0 6f 9d 37 5e  12 11 03                 |....o.7^...|
+00000000  14 03 03 00 01 01 16 03  03 00 40 80 b0 df ff b3  |..........@.....|
+00000010  34 11 03 f5 2d fb c7 c2  38 15 df 41 97 55 0e 1d  |4...-...8..A.U..|
+00000020  36 f7 a5 35 5b 63 d7 c5  a6 fd fc a1 91 32 9d cd  |6..5[c.......2..|
+00000030  34 66 75 4c 5d 27 ee 89  ed d4 4a ec 67 b0 da e7  |4fuL]'....J.g...|
+00000040  f0 e7 36 eb db b9 22 97  74 30 cd                 |..6...".t0.|
 >>> 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 a9 51 94  19 72 ab 9f 3e 97 5e 99  |......Q..r..>.^.|
-00000020  2c ec 13 48 3e 10 54 5f  8a 85 88 4d 1a a8 f5 ed  |,..H>.T_...M....|
-00000030  c3 4f a9 59 a3 15 03 03  00 30 00 00 00 00 00 00  |.O.Y.....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 25 00 6d 2f a0 f6  |..........%.m/..|
-00000050  ce 8a 30 ba 53 da 97 c6  11 f3 d2 f3 9e 66 d6 dd  |..0.S........f..|
-00000060  19 f3 ee 07 03 d3 e6 f1  30 32                    |........02|
+00000010  00 00 00 00 00 62 24 32  e9 40 38 c8 c3 dd 07 42  |.....b$2.@8....B|
+00000020  05 c8 7c 3d d1 27 68 00  e4 91 6c 2d 08 c1 a1 b6  |..|=.'h...l-....|
+00000030  8a 89 3d 1d c1 15 03 03  00 30 00 00 00 00 00 00  |..=......0......|
+00000040  00 00 00 00 00 00 00 00  00 00 d1 c8 bc cb cb a5  |................|
+00000050  24 1e ad c5 bf 23 92 4b  81 a6 c0 77 19 e0 46 30  |$....#.K...w..F0|
+00000060  48 51 0c cc 39 cd 4b 8d  e5 a7                    |HQ..9.K...|
index ff79aa236c569cce02ef8a9fe8489f310211b449..a0a964003144d675658779f5a6a9ed9f25c6ccc7 100644 (file)
@@ -1,67 +1,62 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 51 02 00 00  4d 03 03 b3 b2 22 69 e4  |....Q...M...."i.|
-00000010  1a a1 56 94 26 0c 43 b7  89 0c 34 ce dc 5a c8 ca  |..V.&.C...4..Z..|
-00000020  e2 42 92 5c 75 9a b3 22  22 64 38 20 6d 2c 26 0b  |.B.\u..""d8 m,&.|
-00000030  34 b6 b8 20 36 e2 58 e5  ee 1f e2 9f a0 75 f6 d9  |4.. 6.X......u..|
-00000040  0c e4 39 ce 3c 8e 2e f8  e8 d1 a2 16 00 05 00 00  |..9.<...........|
-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..|
-00000080  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000090  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-000000a0  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-000000b0  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000c0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000d0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000e0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000f0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-00000100  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-00000110  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000120  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000130  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000140  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000150  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000160  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000170  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000180  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000190  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-000001a0  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-000001b0  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001c0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001d0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001e0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001f0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-00000200  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-00000210  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000220  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000230  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000240  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000250  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000260  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000270  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000280  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000290  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-000002a0  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-000002b0  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002c0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002d0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002e0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002f0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-00000300  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 2e 0d 00  |n8P)l...........|
-00000320  00 26 03 01 02 40 00 1e  06 01 06 02 06 03 05 01  |.&...@..........|
-00000330  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
-00000340  02 01 02 02 02 03 00 00  0e 00 00 00              |............|
+00000000  16 03 03 00 51 02 00 00  4d 03 03 60 8e 1c c9 6d  |....Q...M..`...m|
+00000010  de 9d 2a dc 6a a6 82 71  9a 3f 8f 5b 18 52 44 4e  |..*.j..q.?.[.RDN|
+00000020  4d 72 0d e7 c8 a1 b0 81  64 8c 1f 20 06 a8 17 35  |Mr......d.. ...5|
+00000030  b8 0b 96 52 30 f7 b3 d4  2a 25 94 c0 ba a8 a2 f7  |...R0...*%......|
+00000040  86 5c 18 18 3c 68 3a 71  0f bc 3f 12 00 05 00 00  |.\..<h:q..?.....|
+00000050  05 ff 01 00 01 00 16 03  03 02 71 0b 00 02 6d 00  |..........q...m.|
+00000060  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000070  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000080  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000090  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+000000a0  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+000000b0  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000c0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000d0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000e0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000f0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+00000100  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+00000110  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000120  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000130  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000140  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000150  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000160  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000170  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000180  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000190  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+000001a0  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+000001b0  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001c0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001d0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001e0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001f0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+00000200  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+00000210  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f..@....xH.A0.|
+00000220  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000230  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000240  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000250  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H@.-.....|
+00000260  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000270  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000280  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000290  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+000002a0  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+000002b0  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002c0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
+000002d0  2e 0d 00 00 26 03 01 02  40 00 1e 06 01 06 02 06  |....&...@.......|
+000002e0  03 05 01 05 02 05 03 04  01 04 02 04 03 03 01 03  |................|
+000002f0  02 03 03 02 01 02 02 02  03 00 00 0e 00 00 00     |...............|
 >>> Flow 3 (client to server)
 00000000  16 03 03 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|
 000001d0  8b ec ab 67 be c8 64 b0  11 50 46 58 17 6b 99 1c  |...g..d..PFX.k..|
 000001e0  d3 1d fc 06 f1 0e e5 96  a8 0c f9 78 20 b7 44 18  |...........x .D.|
 000001f0  51 8d 10 7e 4f 94 67 df  a3 4e 70 73 8e 90 91 85  |Q..~O.g..Nps....|
-00000200  16 03 03 00 86 10 00 00  82 00 80 6d 51 f3 7f f9  |...........mQ...|
-00000210  3e fb 75 82 41 36 83 e8  6a ee 2a 2e 25 90 67 4c  |>.u.A6..j.*.%.gL|
-00000220  8e 62 2f 30 81 17 e0 85  09 0c 2b b7 23 d7 b0 e2  |.b/0......+.#...|
-00000230  1d f7 3b d7 f5 a1 27 b6  ee 24 b6 1b cc 5b ea 66  |..;...'..$...[.f|
-00000240  0d 6a f4 e5 85 f9 da 43  b4 0e 86 85 e1 f5 aa be  |.j.....C........|
-00000250  c8 ce 39 4c 9c 86 00 08  c2 4b e2 c6 ec 2f f7 ce  |..9L.....K.../..|
-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 05 01 00 80  01 24 8d bb 05 61 2d 29  |.........$...a-)|
-000002a0  12 11 90 f5 57 21 be b7  29 76 55 63 94 8e 7b 4d  |....W!..)vUc..{M|
-000002b0  3b 3d 89 5b 1f b9 e1 8c  36 68 6f 31 21 50 af e4  |;=.[....6ho1!P..|
-000002c0  9f ca a5 68 55 b9 eb 36  75 3a 0c be 11 30 28 c8  |...hU..6u:...0(.|
-000002d0  8b 82 93 9a 71 37 4d 4e  4f d2 0c 2f 13 36 ad c3  |....q7MNO../.6..|
-000002e0  df 8a 1b 59 b2 f9 8b a7  74 63 75 4a f4 9d e0 6b  |...Y....tcuJ...k|
-000002f0  42 02 5a a9 6e a4 a8 24  d3 23 f7 09 ee b0 dc c4  |B.Z.n..$.#......|
-00000300  6f 87 58 72 e7 e3 87 b3  6b 15 ba 7f dd 9b 93 91  |o.Xr....k.......|
-00000310  5b 21 a0 31 31 bd 15 b5  14 03 03 00 01 01 16 03  |[!.11...........|
-00000320  03 00 24 fc 0e 7c e8 3e  8b b5 dc c9 3d 38 61 a1  |..$..|.>....=8a.|
-00000330  24 d6 77 1f 06 1f 30 32  ba dd 05 68 45 f1 4f 0d  |$.w...02...hE.O.|
-00000340  2e 24 09 ad c1 e5 b7                              |.$.....|
+00000200  16 03 03 00 86 10 00 00  82 00 80 73 bd 73 65 92  |...........s.se.|
+00000210  86 23 41 14 79 7f d5 c1  10 ce 94 4d ad 9c c3 a9  |.#A.y......M....|
+00000220  87 b5 32 52 f8 6b 11 93  2d 9b 98 0b 8b 1d c0 f6  |..2R.k..-.......|
+00000230  53 17 6d c7 9c 2e ae c9  6f cc 99 23 38 37 1a 10  |S.m.....o..#87..|
+00000240  fe 05 0b b5 55 0a 14 e9  60 7d 70 26 98 e2 54 d9  |....U...`}p&..T.|
+00000250  65 cf 2e f4 53 5f 1d aa  3a f6 33 7b eb 4c 0e b3  |e...S_..:.3{.L..|
+00000260  ff 5a db 36 2a 47 f3 df  f9 fc f5 31 78 83 aa 6b  |.Z.6*G.....1x..k|
+00000270  52 b7 ba 1a 96 bc fa c1  a1 a9 bb 2b f5 38 89 00  |R..........+.8..|
+00000280  4d e5 78 13 4e a4 38 46  42 dc 16 16 03 03 00 88  |M.x.N.8FB.......|
+00000290  0f 00 00 84 05 01 00 80  21 58 47 70 c2 2e 1c 4a  |........!XGp...J|
+000002a0  fa 97 b2 cf 8d f8 93 f4  b0 8c b3 e0 e7 33 a6 ea  |.............3..|
+000002b0  d7 fe 8e 25 e7 f3 f5 a1  8d 09 b7 0b 01 ec a1 15  |...%............|
+000002c0  5b 67 06 53 2a 7d 31 e5  a8 16 bc e3 1d ed 5a 77  |[g.S*}1.......Zw|
+000002d0  0b 78 78 c5 fc c5 62 8e  41 49 d3 ea cd 69 10 3f  |.xx...b.AI...i.?|
+000002e0  34 9e 86 df f9 9f f6 02  0c 29 c4 66 a0 45 cf 7b  |4........).f.E.{|
+000002f0  ce 51 ec 0a 26 b4 9d 3d  9e 63 5d 40 1a e8 84 4e  |.Q..&..=.c]@...N|
+00000300  24 f5 42 48 b5 3e f8 92  c4 f2 e6 5d f4 ad 67 01  |$.BH.>.....]..g.|
+00000310  f8 a7 a7 2b b5 fc be e8  14 03 03 00 01 01 16 03  |...+............|
+00000320  03 00 24 f0 ec 1d f5 39  1c d2 d2 c7 f4 1f 3b 0c  |..$....9......;.|
+00000330  cd 25 e4 8e ed c4 bb 02  9d 38 e5 a7 91 e0 ea 00  |.%.......8......|
+00000340  73 a8 9a 63 c9 e7 7d                              |s..c..}|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 d7 b6 b3 0a e6  |..........$.....|
-00000010  86 9a 25 e4 38 de d0 57  ff 93 0b f4 de 76 3d 00  |..%.8..W.....v=.|
-00000020  64 35 cf 70 f6 ea 74 2d  b0 71 2d 92 e2 df eb     |d5.p..t-.q-....|
+00000000  14 03 03 00 01 01 16 03  03 00 24 0b c5 7d ca a6  |..........$..}..|
+00000010  87 7f 50 7b 88 9c d9 8e  ea 78 a0 40 6b 8e 92 0b  |..P{.....x.@k...|
+00000020  78 88 97 46 ec 7c 20 5b  1f fc da 49 d8 6a be     |x..F.| [...I.j.|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1a db bd 43  12 7c b5 83 b5 18 9d 6a  |.......C.|.....j|
-00000010  70 3f 5a eb cb d0 ba d4  03 3e a0 7b 25 f0 41 15  |p?Z......>.{%.A.|
-00000020  03 03 00 16 f8 f2 a3 27  a5 c7 25 d9 6c 08 b1 96  |.......'..%.l...|
-00000030  38 22 38 df 16 fb e2 9f  61 a3                    |8"8.....a.|
+00000000  17 03 03 00 1a 16 25 97  df 98 e4 d6 8e d1 2c 0c  |......%.......,.|
+00000010  27 74 67 e5 b7 f1 c7 58  41 5f 04 f5 e4 74 dc 15  |'tg....XA_...t..|
+00000020  03 03 00 16 df 55 01 0d  53 5b b4 36 c7 88 8d b0  |.....U..S[.6....|
+00000030  22 53 ec 87 1b 07 c7 9d  af 89                    |"S........|
index e700e16352a692cca48ce48dc141b5d317fecde7..c9b5351f45ce47a0ac7c4b40837465af7d92595a 100644 (file)
@@ -1,19 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 21 9b eb 15 24  |....Y...U..!...$|
-00000010  46 b6 c1 85 f5 be c5 0d  e2 6b 60 bc ee 73 b1 fb  |F........k`..s..|
-00000020  34 6f f0 b8 f0 9e 1c 26  a4 4b 0f 20 cb 2b 84 a2  |4o.....&.K. .+..|
-00000030  cb a5 48 70 fe 84 25 b0  16 20 14 a1 83 21 fc f9  |..Hp..%.. ...!..|
-00000040  82 fc 9e 1a d1 3b 56 69  ab c5 0e 2c c0 09 00 00  |.....;Vi...,....|
+00000000  16 03 03 00 59 02 00 00  55 03 03 8a ae 27 5b 39  |....Y...U....'[9|
+00000010  8b c4 a6 d5 fa 9e 67 9e  6c fe 53 ed ab ec e0 04  |......g.l.S.....|
+00000020  8d 7c f8 1f d0 db 2e cb  22 4d a1 20 ee 80 5f fc  |.|......"M. .._.|
+00000030  f8 77 8a 23 23 c5 95 81  7f a6 12 f5 e0 19 91 50  |.w.##..........P|
+00000040  da 75 42 c2 eb 45 bf e2  a5 54 ed 6e c0 09 00 00  |.uB..E...T.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....|
 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 b6  |*............A..|
-00000280  3f 37 33 68 cb 79 c0 86  f4 9d 12 ac c4 9d 8c 9b  |?73h.y..........|
-00000290  59 1c d4 a9 01 9f 2d cb  80 24 02 ec e0 ff d1 8c  |Y.....-..$......|
-000002a0  bd 82 67 3f 47 58 1a 2e  6b 61 f6 8e 4e 27 7f 49  |..g?GX..ka..N'.I|
-000002b0  b5 45 f1 0b 9a 33 ff 53  ac 65 e2 82 7a 18 5c 04  |.E...3.S.e..z.\.|
-000002c0  03 00 8b 30 81 88 02 42  00 e1 2d ff 5d e7 77 f1  |...0...B..-.].w.|
-000002d0  12 d9 e4 c2 4d cd 9c b5  ee e4 fd 21 b2 d8 53 a9  |....M......!..S.|
-000002e0  42 e7 c5 9b 51 c3 59 37  a5 08 d4 e6 29 12 c5 56  |B...Q.Y7....)..V|
-000002f0  b8 fe f0 bb 77 87 a3 ee  09 b0 8c cd 1c 39 9e b5  |....w........9..|
-00000300  d9 15 63 53 cb d7 f1 55  5b 48 02 42 01 19 10 8a  |..cS...U[H.B....|
-00000310  7a ee 95 b1 77 44 d4 a3  bf d1 f3 f1 b0 d8 c7 7e  |z...wD.........~|
-00000320  42 c0 83 04 f5 f7 9c c0  ce 6a 98 47 9d 21 29 84  |B........j.G.!).|
-00000330  c8 be 6b 67 4e fc c6 26  ec 63 df 00 33 e6 d2 f7  |..kgN..&.c..3...|
-00000340  34 93 85 9b 1b 0f e0 89  42 b6 0b 94 1b 80 16 03  |4.......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 3e  |*............A.>|
+00000280  e3 d6 d6 7b d7 ec 6f 4b  88 50 53 26 5a 2b a6 69  |...{..oK.PS&Z+.i|
+00000290  25 6f 30 a7 c3 a5 39 5c  e2 ca b6 35 a5 30 35 9a  |%o0...9\...5.05.|
+000002a0  35 8f e3 65 bd 4c 47 30  72 9a 4b 32 c4 6d 01 c9  |5..e.LG0r.K2.m..|
+000002b0  a5 91 d1 cd 0b 79 e2 04  0f a9 9c c2 72 cd 58 04  |.....y......r.X.|
+000002c0  03 00 8a 30 81 87 02 41  70 01 8c dd 0a 32 db e3  |...0...Ap....2..|
+000002d0  0b 04 9c d0 64 a1 08 06  b1 cf e3 66 79 1f c0 c1  |....d......fy...|
+000002e0  14 34 87 a6 e5 52 11 20  12 24 a5 b6 c2 50 63 86  |.4...R. .$...Pc.|
+000002f0  31 6a e3 85 7d 19 2d 3b  68 bf b7 64 20 37 c7 f9  |1j..}.-;h..d 7..|
+00000300  76 38 b5 32 84 0b f9 b6  71 02 42 01 89 e3 93 85  |v8.2....q.B.....|
+00000310  d6 16 8e 44 66 72 d6 9f  b3 b1 e9 22 ad 2e f8 49  |...Dfr....."...I|
+00000320  41 8f 80 f9 0e d4 fd de  35 67 cf 09 ba 65 f7 a1  |A.......5g...e..|
+00000330  17 a8 c0 b5 a3 cc c0 17  83 af 68 92 5b 5c a9 ce  |..........h.[\..|
+00000340  ce 11 92 93 fe 39 b9 80  19 20 f2 b6 3b 16 03 03  |.....9... ..;...|
+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.|
 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 50 73  9c 9f a8 d7 78 ac 06 14  |......Ps....x...|
-00000070  8f ae fc fb ef 7d 99 db  b7 c9 91 dd f2 fe da 1b  |.....}..........|
-00000080  aa 9e 7d e4 5c 2f 5f dd  74 aa fe 03 51 e7 cd 98  |..}.\/_.t...Q...|
-00000090  e9 21 19 c9 6f 59                                 |.!..oY|
+00000060  00 00 00 00 00 00 39 19  e6 fb c7 28 b4 c9 f5 ba  |......9....(....|
+00000070  a2 44 0a 74 70 18 86 1f  5f c2 3d 99 f5 d7 17 04  |.D.tp..._.=.....|
+00000080  88 07 a5 06 01 6a 2c 13  55 0b fc 82 75 b5 24 54  |.....j,.U...u.$T|
+00000090  a0 63 9e f0 ce 92                                 |.c....|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 40 47 18 b5 1b 75  |..........@G...u|
-00000010  b8 a3 63 ab 77 d3 47 cb  14 26 b4 88 fe 15 db 22  |..c.w.G..&....."|
-00000020  76 3b 25 d3 68 8e f2 a7  d5 03 2b 82 7b b1 0f 10  |v;%.h.....+.{...|
-00000030  49 6a 3d 95 d0 4b 55 0e  14 eb bb a7 34 bb 57 b3  |Ij=..KU.....4.W.|
-00000040  5d fb 7e 15 80 5a fa f3  3a df 90                 |].~..Z..:..|
+00000000  14 03 03 00 01 01 16 03  03 00 40 15 37 89 e6 1f  |..........@.7...|
+00000010  20 f6 91 b9 1f fb 29 e9  3e 07 ab c2 09 96 06 89  | .....).>.......|
+00000020  69 c2 dd 63 e1 24 5d cd  af 08 e2 ed df 46 45 6b  |i..c.$]......FEk|
+00000030  1e 9f 62 b6 89 27 04 3f  fc f2 77 71 23 04 24 37  |..b..'.?..wq#.$7|
+00000040  74 8a 0a 64 a8 10 e3 1c  dc 53 64                 |t..d.....Sd|
 >>> 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 70 74 e2  60 fc 3a 7a b7 5e 16 07  |.....pt.`.:z.^..|
-00000020  22 92 07 fe 92 53 c4 43  1b 8f 94 07 84 48 2b 50  |"....S.C.....H+P|
-00000030  ab 1d 6d 49 ed 15 03 03  00 30 00 00 00 00 00 00  |..mI.....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 ce a8 ba 91 0b e4  |................|
-00000050  8c 38 23 9b 8b 2c 0a 0c  63 79 61 f4 b6 25 f7 41  |.8#..,..cya..%.A|
-00000060  04 9f b0 8f e0 e5 24 44  2f e9                    |......$D/.|
+00000010  00 00 00 00 00 ae 4e e7  3a 25 9d 8f fa 06 99 49  |......N.:%.....I|
+00000020  2e b8 0f 49 d0 54 2d 06  b4 d7 4c 60 51 f1 13 11  |...I.T-...L`Q...|
+00000030  c1 b3 f5 d0 bc 15 03 03  00 30 00 00 00 00 00 00  |.........0......|
+00000040  00 00 00 00 00 00 00 00  00 00 80 de bf db 10 74  |...............t|
+00000050  da 3f d8 77 ca 37 cc f3  96 bd d3 e1 34 9c f2 0a  |.?.w.7......4...|
+00000060  70 60 5e 7c a4 7e c9 bd  89 5f                    |p`^|.~..._|
index 607ecdcb2407fac950a092a79597d79e9769445e..48d822a39c9c5510b9dbceedc363fcf8c09d1a1f 100644 (file)
@@ -1,19 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 91 8a 4f 94 29  |....Y...U....O.)|
-00000010  32 fa 66 7a 7f b8 a7 04  5c 34 b9 7e 12 83 35 1f  |2.fz....\4.~..5.|
-00000020  93 b0 af e0 9f 71 07 5e  2f d7 ca 20 52 dc 0d e7  |.....q.^/.. R...|
-00000030  f8 16 db 90 9a 78 2f 03  0b f0 ae a7 2f c6 b4 4c  |.....x/...../..L|
-00000040  62 e7 de 32 d5 68 61 f3  07 e4 60 d2 c0 2b 00 00  |b..2.ha...`..+..|
+00000000  16 03 03 00 59 02 00 00  55 03 03 42 ab c5 81 f5  |....Y...U..B....|
+00000010  c0 5b 73 64 f6 1b e0 59  30 b0 fd c5 e6 b3 57 f2  |.[sd...Y0.....W.|
+00000020  28 3f 5c d2 e8 05 7d a8  29 84 2e 20 8e 18 6b 52  |(?\...}.).. ..kR|
+00000030  1b ee 03 02 64 52 fb 24  44 4f 39 f2 d3 0f e6 9d  |....dR.$DO9.....|
+00000040  50 31 31 b3 39 9e c1 3a  b3 67 41 a0 c0 2b 00 00  |P11.9..:.gA..+..|
 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....|
 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 26  |*............A.&|
-00000280  c1 67 14 4b 9e b0 45 8c  27 bf a3 a2 78 5b 56 ad  |.g.K..E.'...x[V.|
-00000290  d1 21 56 53 df 86 e9 91  de e3 f9 5d e6 f6 5d 79  |.!VS.......]..]y|
-000002a0  11 8b 60 f9 c2 9a c6 3f  6b 72 cd 7c d7 0e 13 64  |..`....?kr.|...d|
-000002b0  af e8 9f 40 35 e6 fb 04  0c 60 aa 19 61 dd 24 04  |...@5....`..a.$.|
-000002c0  03 00 8b 30 81 88 02 42  00 9d e1 02 5d 8b b1 45  |...0...B....]..E|
-000002d0  e5 c7 b6 94 27 df 36 31  fd 5e 47 fe c8 0f 5f 17  |....'.61.^G..._.|
-000002e0  b1 92 56 76 29 45 3d 90  be 91 6e 2c a7 b2 e1 33  |..Vv)E=...n,...3|
-000002f0  3b f9 3c bb 80 58 c2 d8  a8 59 82 16 dc 9e dd 60  |;.<..X...Y.....`|
-00000300  ff 82 b9 0c 5a ca ff f3  02 2c 02 42 00 a4 c0 d3  |....Z....,.B....|
-00000310  aa 1d 69 52 c0 06 fa 93  e8 50 da a4 2f 72 c9 4a  |..iR.....P../r.J|
-00000320  2c 43 7f 95 05 f7 7a f3  4a 2e 2d ce 13 be 80 40  |,C....z.J.-....@|
-00000330  a4 3b b2 f0 73 8d f1 d4  7b a3 ff 01 e1 58 71 31  |.;..s...{....Xq1|
-00000340  fc d8 2f b3 ef 62 2e b7  ac f5 c4 bc b8 68 16 03  |../..b.......h..|
+00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 7a  |*............A.z|
+00000280  01 b4 2c 50 85 34 6e 2c  2c 52 bc fa cf 71 82 e5  |..,P.4n,,R...q..|
+00000290  98 8d b0 f1 65 5f 7d bc  c8 1b 7c 84 3e 46 45 c5  |....e_}...|.>FE.|
+000002a0  43 0e 72 e1 90 63 40 26  1c 22 dc 9a 3b b8 12 26  |C.r..c@&."..;..&|
+000002b0  a9 d6 1c e1 44 cf c7 38  db 9e 1b d0 b9 bb 06 04  |....D..8........|
+000002c0  03 00 8b 30 81 88 02 42  01 6b af f8 34 ae 89 50  |...0...B.k..4..P|
+000002d0  df 44 20 16 0b f9 ef a9  99 63 39 48 39 08 69 2d  |.D ......c9H9.i-|
+000002e0  2d 9d 8b 3a e8 8a 9c 2f  e9 d2 85 f2 d3 54 53 ec  |-..:.../.....TS.|
+000002f0  b7 18 5b b0 76 3c 38 02  85 cc 00 20 45 9d e7 ba  |..[.v<8.... E...|
+00000300  c0 3f c0 b5 1f df 64 42  fd 34 02 42 00 fa e5 dd  |.?....dB.4.B....|
+00000310  04 c4 60 60 ff 9b 95 a2  a4 b4 80 87 9f 59 b4 8e  |..``.........Y..|
+00000320  72 bf 53 8e 61 b6 df 99  9d 81 05 c5 71 a2 00 cb  |r.S.a.......q...|
+00000330  80 bd e5 2a c3 51 d0 45  2f a3 8b 6d 21 6e 6c 80  |...*.Q.E/..m!nl.|
+00000340  4e f1 28 23 6d 76 df 55  77 69 a1 be 39 05 16 03  |N.(#mv.Uwi..9...|
 00000350  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..|
 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 83 cf  |.....(..........|
-00000060  ef 50 c2 e7 da b9 74 7f  1c e0 b8 fb dc 39 c9 98  |.P....t......9..|
-00000070  0c a3 7d 8c c6 fa 6f f2  ee 44 a0 a0 03 18        |..}...o..D....|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 94 ba  |.....(..........|
+00000060  0a c6 38 6b 65 60 95 5e  df fc 42 7e ac 9f 5a 25  |..8ke`.^..B~..Z%|
+00000070  39 0e a9 7a 61 b3 17 80  77 82 e5 80 0a af        |9..za...w.....|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 73 c4 48 24 3d  |..........(s.H$=|
-00000010  8f 5f f3 8c fc fd 63 be  64 39 d5 56 67 bd d7 c4  |._....c.d9.Vg...|
-00000020  0d 57 88 1a 45 a6 f3 ad  11 b2 5a 41 58 33 f3 d3  |.W..E.....ZAX3..|
-00000030  58 fa 21                                          |X.!|
+00000000  14 03 03 00 01 01 16 03  03 00 28 ef 8d ac 17 6f  |..........(....o|
+00000010  88 03 88 8f f3 d5 a0 60  28 a9 4d e8 20 ae 0c 21  |.......`(.M. ..!|
+00000020  fd d1 50 9b c3 d1 e9 cd  27 ed d7 8b 92 60 49 47  |..P.....'....`IG|
+00000030  ed 9a 74                                          |..t|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 65 5e 55  |.............e^U|
-00000010  32 be 00 77 6e 1d 8e 8f  95 33 24 3d 7a c2 b0 3f  |2..wn....3$=z..?|
-00000020  ca aa 97 15 03 03 00 1a  00 00 00 00 00 00 00 02  |................|
-00000030  b2 71 6e 42 6a 0d cf c9  ac 14 a4 b5 9c c9 71 60  |.qnBj.........q`|
-00000040  d7 c2                                             |..|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 1d 4f 3c  |..............O<|
+00000010  c5 d1 39 01 46 ab 7d d1  75 59 e7 f5 cd fa 02 0b  |..9.F.}.uY......|
+00000020  dd 02 17 15 03 03 00 1a  00 00 00 00 00 00 00 02  |................|
+00000030  e9 a5 d5 0c 05 2a 82 fe  a5 6c 03 6e d0 c4 7d cb  |.....*...l.n..}.|
+00000040  32 f3                                             |2.|
index df2f7376de8b8cdb6f9983367971960f041fe10a..2a16651136c4d5b927cb1327b5be00c90e4cc142 100644 (file)
@@ -1,19 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 11 50 81 a7 ef  |....Y...U...P...|
-00000010  3f bd a5 a9 41 11 e6 86  b2 a3 d8 bf 29 c3 d4 f4  |?...A.......)...|
-00000020  b6 20 2d cb 94 1b 0e dd  99 d1 0b 20 78 92 23 31  |. -........ x.#1|
-00000030  e3 fc 99 67 1f fd f3 2a  fc 9c 4c 74 6e 32 e4 f8  |...g...*..Ltn2..|
-00000040  ed 6d 2e 6d ad a9 a9 bf  63 27 7e 44 c0 2c 00 00  |.m.m....c'~D.,..|
+00000000  16 03 03 00 59 02 00 00  55 03 03 ed 6d 5a 1c 89  |....Y...U...mZ..|
+00000010  a4 f3 35 0b e4 74 7e e2  05 a5 36 4d 4a 55 b3 7c  |..5..t~...6MJU.||
+00000020  a1 a6 42 a3 fc 35 8c e0  97 5b 4b 20 a1 4a 06 28  |..B..5...[K .J.(|
+00000030  4d 40 0b fc 47 d5 4d 9b  d5 43 b0 0d 0d c6 ae 30  |M@..G.M..C.....0|
+00000040  79 59 00 d4 90 96 98 92  d2 3a 57 07 c0 2c 00 00  |yY.......:W..,..|
 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....|
 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 d7 0c 00  00 d3 03 00 17 41 04 fc  |*............A..|
-00000280  e6 25 27 3c 76 10 a8 9e  d3 a4 a8 68 31 06 85 fc  |.%'<v......h1...|
-00000290  35 2a 76 b3 ad 08 c5 70  ed 3d 61 e0 29 cc 47 52  |5*v....p.=a.).GR|
-000002a0  68 21 ab 48 19 f9 28 ba  54 8c 56 8e b0 7d 55 7f  |h!.H..(.T.V..}U.|
-000002b0  75 f5 42 38 61 ff e2 06  98 1a ae fc bc a0 3a 04  |u.B8a.........:.|
-000002c0  03 00 8a 30 81 87 02 42  01 0c b2 7f c9 d3 1b 83  |...0...B........|
-000002d0  1e 24 a3 d7 1c 81 f0 02  ae ed 42 6f e9 d9 91 4d  |.$........Bo...M|
-000002e0  16 5f aa 8e 5a de 3b 00  0e e6 2d fb 05 30 f3 cf  |._..Z.;...-..0..|
-000002f0  31 a2 ec 99 87 ea 42 03  0a 57 82 e5 12 27 98 8a  |1.....B..W...'..|
-00000300  c6 56 4b 9a 0b d7 37 5f  46 50 02 41 57 61 13 3c  |.VK...7_FP.AWa.<|
-00000310  48 d0 b3 b0 d5 21 72 49  80 7b d7 ef 8f 0d a0 c5  |H....!rI.{......|
-00000320  88 a1 5d ca 61 6d fb 8b  51 15 5d e5 a2 61 c4 78  |..].am..Q.]..a.x|
-00000330  8f d9 e3 78 df 7d a0 8f  0c c0 cc 18 36 41 e6 bb  |...x.}......6A..|
-00000340  6d e3 9d 04 c2 c4 d0 66  35 45 9a 08 b2 16 03 03  |m......f5E......|
+00000270  2a 16 03 03 00 d7 0c 00  00 d3 03 00 17 41 04 89  |*............A..|
+00000280  e6 6d 6a 56 3e e5 4e 72  df 2b 41 11 de a0 c0 3e  |.mjV>.Nr.+A....>|
+00000290  22 04 9a b5 a8 d6 22 30  2a e5 bd 83 1c 7a 8e 6c  |"....."0*....z.l|
+000002a0  93 ab 8f d7 64 9e fe 89  c0 da 9a 45 7d 76 91 69  |....d......E}v.i|
+000002b0  0a 11 c5 59 26 49 ec 69  99 b3 91 a5 4b 2b 89 04  |...Y&I.i....K+..|
+000002c0  03 00 8a 30 81 87 02 42  01 17 1d ff 9a 99 76 20  |...0...B......v |
+000002d0  13 8a e1 5a a8 04 8a 1e  84 57 fd b0 95 c1 6c af  |...Z.....W....l.|
+000002e0  b2 66 13 b5 75 36 ce 86  69 67 3d dc 82 2f 06 57  |.f..u6..ig=../.W|
+000002f0  19 14 56 54 0e 8e 04 74  0b 73 49 61 92 8e d1 9a  |..VT...t.sIa....|
+00000300  b5 60 7f 65 a8 f8 99 eb  ac 56 02 41 57 a3 78 57  |.`.e.....V.AW.xW|
+00000310  8a dd fa 9c 3d 24 a0 f2  0a 74 1a 8a 8f 6c 82 55  |....=$...t...l.U|
+00000320  4c cd d8 5d 79 99 87 93  41 e7 78 f4 28 0d ef 63  |L..]y...A.x.(..c|
+00000330  fb da 8e 93 86 31 6e 3e  ca 6f 6b 1b fd 7a a3 86  |.....1n>.ok..z..|
+00000340  6e bb 17 35 90 d9 a4 df  12 d0 54 5e 25 16 03 03  |n..5......T^%...|
 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..|
 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 a3 3f  |.....(.........?|
-00000060  be 65 91 cd fe 37 43 e0  ea 6f 15 9d c2 aa 6a 02  |.e...7C..o....j.|
-00000070  20 b8 bc b5 c8 9a 1c d4  c4 e5 9b 2e 39 e7        | ...........9.|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 9d e7  |.....(..........|
+00000060  31 2a 0a 46 84 fd d9 18  c2 b0 b1 31 eb 63 4d 2d  |1*.F.......1.cM-|
+00000070  ee 17 59 e6 b4 0f c6 d8  3d 8c e9 57 83 a8        |..Y.....=..W..|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 7c b7 1f 13 9e  |..........(|....|
-00000010  21 d2 eb db 32 fc 36 d0  53 e1 11 04 ce d0 61 33  |!...2.6.S.....a3|
-00000020  1e 30 3d 91 c3 6a 0d 98  55 f5 e0 5c ca 77 fa 72  |.0=..j..U..\.w.r|
-00000030  63 6a be                                          |cj.|
+00000000  14 03 03 00 01 01 16 03  03 00 28 e0 85 25 02 b4  |..........(..%..|
+00000010  86 32 57 70 3c 7e 6b e5  75 e0 3a 43 c8 c2 fe f8  |.2Wp<~k.u.:C....|
+00000020  2e 04 fe 73 e4 7b 2c 9a  e0 65 2e d6 53 ae f1 19  |...s.{,..e..S...|
+00000030  dd 6f 1a                                          |.o.|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 d9 db db  |................|
-00000010  4b 3a ae 5c a4 dc 96 33  ed b5 a0 70 64 1f 96 2f  |K:.\...3...pd../|
-00000020  b6 cd 1e 15 03 03 00 1a  00 00 00 00 00 00 00 02  |................|
-00000030  18 a0 d1 98 a6 71 c9 56  36 bd 1a 46 4b 5b 45 29  |.....q.V6..FK[E)|
-00000040  1f dd                                             |..|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 29 b2 e6  |.............)..|
+00000010  c3 2e 72 ba cc ac d9 3b  c7 0c 1d 53 b2 30 39 71  |..r....;...S.09q|
+00000020  6e dd 79 15 03 03 00 1a  00 00 00 00 00 00 00 02  |n.y.............|
+00000030  88 c9 92 fe 6c 1f 6c fd  bd 7b fb 0a 8a b5 cc c9  |....l.l..{......|
+00000040  94 90                                             |..|
index 994ebb1e37f94b4eb4b5c06f77dedfbf1cf823a6..29767b7b93683eafd39cdc1ebc8c6edec0d5a8ac 100644 (file)
@@ -1,78 +1,73 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 e6 ae 89 0d 22  |....Y...U......"|
-00000010  e5 e0 cd 57 a3 ca 71 4f  17 2f 64 77 f8 30 89 ef  |...W..qO./dw.0..|
-00000020  e8 19 70 ac dd 2c c5 9f  84 7d 1d 20 1c 59 3c fe  |..p..,...}. .Y<.|
-00000030  a9 ec 10 dd 38 3b 43 fe  6b 09 e5 e4 83 d9 7a 78  |....8;C.k.....zx|
-00000040  86 08 33 da 9b e1 09 d8  c9 07 34 19 c0 13 00 00  |..3.......4.....|
+00000000  16 03 03 00 59 02 00 00  55 03 03 2a 6a a8 b3 97  |....Y...U..*j...|
+00000010  d5 c8 5e b4 22 7e d0 a5  c7 46 af 89 60 44 77 5e  |..^."~...F..`Dw^|
+00000020  1a f8 3a 30 08 6d 5f 4c  61 36 c5 20 57 79 91 3e  |..:0.m_La6. Wy.>|
+00000030  1f 40 d1 f1 33 d7 a9 fb  93 eb 16 0d e1 39 e3 a3  |.@..3........9..|
+00000040  80 e3 4f 58 a6 f8 a4 be  19 dd ef ee c0 13 00 00  |..OX............|
 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..............|
-00000080  a4 8a 7f b8 ca 30 0d 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
-00000090  01 05 05 00 30 45 31 0b  30 09 06 03 55 04 06 13  |....0E1.0...U...|
-000000a0  02 41 55 31 13 30 11 06  03 55 04 08 13 0a 53 6f  |.AU1.0...U....So|
-000000b0  6d 65 2d 53 74 61 74 65  31 21 30 1f 06 03 55 04  |me-State1!0...U.|
-000000c0  0a 13 18 49 6e 74 65 72  6e 65 74 20 57 69 64 67  |...Internet Widg|
-000000d0  69 74 73 20 50 74 79 20  4c 74 64 30 1e 17 0d 31  |its Pty Ltd0...1|
-000000e0  30 30 34 32 34 30 39 30  39 33 38 5a 17 0d 31 31  |00424090938Z..11|
-000000f0  30 34 32 34 30 39 30 39  33 38 5a 30 45 31 0b 30  |0424090938Z0E1.0|
-00000100  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
-00000110  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
-00000120  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
-00000130  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
-00000140  74 64 30 81 9f 30 0d 06  09 2a 86 48 86 f7 0d 01  |td0..0...*.H....|
-00000150  01 01 05 00 03 81 8d 00  30 81 89 02 81 81 00 bb  |........0.......|
-00000160  79 d6 f5 17 b5 e5 bf 46  10 d0 dc 69 be e6 2b 07  |y......F...i..+.|
-00000170  43 5a d0 03 2d 8a 7a 43  85 b7 14 52 e7 a5 65 4c  |CZ..-.zC...R..eL|
-00000180  2c 78 b8 23 8c b5 b4 82  e5 de 1f 95 3b 7e 62 a5  |,x.#........;~b.|
-00000190  2c a5 33 d6 fe 12 5c 7a  56 fc f5 06 bf fa 58 7b  |,.3...\zV.....X{|
-000001a0  26 3f b5 cd 04 d3 d0 c9  21 96 4a c7 f4 54 9f 5a  |&?......!.J..T.Z|
-000001b0  bf ef 42 71 00 fe 18 99  07 7f 7e 88 7d 7d f1 04  |..Bq......~.}}..|
-000001c0  39 c4 a2 2e db 51 c9 7c  e3 c0 4c 3b 32 66 01 cf  |9....Q.|..L;2f..|
-000001d0  af b1 1d b8 71 9a 1d db  db 89 6b ae da 2d 79 02  |....q.....k..-y.|
-000001e0  03 01 00 01 a3 81 a7 30  81 a4 30 1d 06 03 55 1d  |.......0..0...U.|
-000001f0  0e 04 16 04 14 b1 ad e2  85 5a cf cb 28 db 69 ce  |.........Z..(.i.|
-00000200  23 69 de d3 26 8e 18 88  39 30 75 06 03 55 1d 23  |#i..&...90u..U.#|
-00000210  04 6e 30 6c 80 14 b1 ad  e2 85 5a cf cb 28 db 69  |.n0l......Z..(.i|
-00000220  ce 23 69 de d3 26 8e 18  88 39 a1 49 a4 47 30 45  |.#i..&...9.I.G0E|
-00000230  31 0b 30 09 06 03 55 04  06 13 02 41 55 31 13 30  |1.0...U....AU1.0|
-00000240  11 06 03 55 04 08 13 0a  53 6f 6d 65 2d 53 74 61  |...U....Some-Sta|
-00000250  74 65 31 21 30 1f 06 03  55 04 0a 13 18 49 6e 74  |te1!0...U....Int|
-00000260  65 72 6e 65 74 20 57 69  64 67 69 74 73 20 50 74  |ernet Widgits Pt|
-00000270  79 20 4c 74 64 82 09 00  85 b0 bb a4 8a 7f b8 ca  |y Ltd...........|
-00000280  30 0c 06 03 55 1d 13 04  05 30 03 01 01 ff 30 0d  |0...U....0....0.|
-00000290  06 09 2a 86 48 86 f7 0d  01 01 05 05 00 03 81 81  |..*.H...........|
-000002a0  00 08 6c 45 24 c7 6b b1  59 ab 0c 52 cc f2 b0 14  |..lE$.k.Y..R....|
-000002b0  d7 87 9d 7a 64 75 b5 5a  95 66 e4 c5 2b 8e ae 12  |...zdu.Z.f..+...|
-000002c0  66 1f eb 4f 38 b3 6e 60  d3 92 fd f7 41 08 b5 25  |f..O8.n`....A..%|
-000002d0  13 b1 18 7a 24 fb 30 1d  ba ed 98 b9 17 ec e7 d7  |...z$.0.........|
-000002e0  31 59 db 95 d3 1d 78 ea  50 56 5c d5 82 5a 2d 5a  |1Y....x.PV\..Z-Z|
-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 77  |.............A.w|
-00000330  87 a7 ad f6 f8 34 82 05  ef bb 14 6d c7 8b 7b 2a  |.....4.....m..{*|
-00000340  4d ca 41 65 58 3c 83 fa  4d ce 0c 74 46 85 fe 38  |M.AeX<..M..tF..8|
-00000350  95 80 ee 7c c2 bf f2 be  a3 c6 bf f3 aa 07 23 40  |...|..........#@|
-00000360  7e cc 74 4a 4e 2e 69 af  6b e0 42 8a fc 41 be 04  |~.tJN.i.k.B..A..|
-00000370  01 00 80 99 ed a8 3a ef  93 1b 4c 17 80 9e cc eb  |......:...L.....|
-00000380  da 39 fb c8 9a 73 e1 96  20 3e 41 fa 8b 1a b1 68  |.9...s.. >A....h|
-00000390  cd 47 bc 4b 7b 0c 14 da  87 d3 36 09 5e 37 33 88  |.G.K{.....6.^73.|
-000003a0  7f 88 07 87 46 ec e5 72  a8 59 92 07 fa 4d 02 dc  |....F..r.Y...M..|
-000003b0  bf 3a f5 e4 77 0b a6 85  ce 43 ee 1b 90 30 7f ec  |.:..w....C...0..|
-000003c0  88 79 f8 88 59 af 6b 7f  2d 88 de 92 cd c8 36 cf  |.y..Y.k.-.....6.|
-000003d0  ba b9 08 6a c4 3d d7 9a  48 50 e1 67 d0 62 a5 b3  |...j.=..HP.g.b..|
-000003e0  b0 5f 2e 16 ee 4d 7d a2  cf d9 93 19 89 b7 64 0f  |._...M}.......d.|
-000003f0  0f 8e 3d 16 03 03 00 04  0e 00 00 00              |..=.........|
+00000060  03 02 71 0b 00 02 6d 00  02 6a 00 02 67 30 82 02  |..q...m..j..g0..|
+00000070  63 30 82 01 cc a0 03 02  01 02 02 09 00 a2 73 00  |c0............s.|
+00000080  0c 81 00 cb f3 30 0d 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
+00000090  01 0b 05 00 30 2b 31 17  30 15 06 03 55 04 0a 13  |....0+1.0...U...|
+000000a0  0e 47 6f 6f 67 6c 65 20  54 45 53 54 49 4e 47 31  |.Google TESTING1|
+000000b0  10 30 0e 06 03 55 04 03  13 07 47 6f 20 52 6f 6f  |.0...U....Go Roo|
+000000c0  74 30 1e 17 0d 31 35 30  31 30 31 30 30 30 30 30  |t0...15010100000|
+000000d0  30 5a 17 0d 32 35 30 31  30 31 30 30 30 30 30 30  |0Z..250101000000|
+000000e0  5a 30 26 31 17 30 15 06  03 55 04 0a 13 0e 47 6f  |Z0&1.0...U....Go|
+000000f0  6f 67 6c 65 20 54 45 53  54 49 4e 47 31 0b 30 09  |ogle TESTING1.0.|
+00000100  06 03 55 04 03 13 02 47  6f 30 81 9f 30 0d 06 09  |..U....Go0..0...|
+00000110  2a 86 48 86 f7 0d 01 01  01 05 00 03 81 8d 00 30  |*.H............0|
+00000120  81 89 02 81 81 00 af 87  88 f6 20 1b 95 65 6c 14  |.......... ..el.|
+00000130  ab 44 05 af 3b 45 14 e3  b7 6d fd 00 63 4d 95 7f  |.D..;E...m..cM..|
+00000140  fe 6a 62 35 86 c0 4a f9  18 7c f6 aa 25 5e 7a 64  |.jb5..J..|..%^zd|
+00000150  31 66 00 ba f4 8e 92 af  c7 6b d8 76 d4 f3 5f 41  |1f.......k.v.._A|
+00000160  cb 6e 56 15 97 1b 97 c1  3c 12 39 21 66 3d 2b 16  |.nV.....<.9!f=+.|
+00000170  d1 bc db 1c c0 a7 da b7  ca ad ba da cb d5 21 50  |..............!P|
+00000180  ec de 8d ab d1 6b 81 4b  89 02 f3 c4 be c1 6c 89  |.....k.K......l.|
+00000190  b1 44 84 bd 21 d1 04 7d  9d 16 4d f9 82 15 f6 ef  |.D..!..}..M.....|
+000001a0  fa d6 09 47 f2 fb 02 03  01 00 01 a3 81 93 30 81  |...G..........0.|
+000001b0  90 30 0e 06 03 55 1d 0f  01 01 ff 04 04 03 02 05  |.0...U..........|
+000001c0  a0 30 1d 06 03 55 1d 25  04 16 30 14 06 08 2b 06  |.0...U.%..0...+.|
+000001d0  01 05 05 07 03 01 06 08  2b 06 01 05 05 07 03 02  |........+.......|
+000001e0  30 0c 06 03 55 1d 13 01  01 ff 04 02 30 00 30 19  |0...U.......0.0.|
+000001f0  06 03 55 1d 0e 04 12 04  10 12 50 8d 89 6f 1b d1  |..U.......P..o..|
+00000200  dc 54 4d 6e cb 69 5e 06  f4 30 1b 06 03 55 1d 23  |.TMn.i^..0...U.#|
+00000210  04 14 30 12 80 10 bf 3d  b6 a9 66 f2 b8 40 cf ea  |..0....=..f..@..|
+00000220  b4 03 78 48 1a 41 30 19  06 03 55 1d 11 04 12 30  |..xH.A0...U....0|
+00000230  10 82 0e 65 78 61 6d 70  6c 65 2e 67 6f 6c 61 6e  |...example.golan|
+00000240  67 30 0d 06 09 2a 86 48  86 f7 0d 01 01 0b 05 00  |g0...*.H........|
+00000250  03 81 81 00 92 7c af 91  55 12 18 96 59 31 a6 48  |.....|..U...Y1.H|
+00000260  40 d5 2d d5 ee bb 02 a0  f5 c2 1e 7c 9b b3 30 7d  |@.-........|..0}|
+00000270  3c dc 76 da 4f 3d c0 fa  ae 2d 33 24 6b 03 7b 1b  |<.v.O=...-3$k.{.|
+00000280  67 59 11 21 b5 11 bc 77  b9 d9 e0 6e a8 2d 2e 35  |gY.!...w...n.-.5|
+00000290  fa 64 5f 22 3e 63 10 6b  be ff 14 86 6d 0d f0 15  |.d_">c.k....m...|
+000002a0  31 a8 14 38 1e 3b 84 87  2c cb 98 ed 51 76 b9 b1  |1..8.;..,...Qv..|
+000002b0  4f dd db 9b 84 04 86 40  fa 51 dd ba b4 8d eb e3  |O......@.Q......|
+000002c0  46 de 46 b9 4f 86 c7 f9  a4 c2 41 34 ac cc f6 ea  |F.F.O.....A4....|
+000002d0  b0 ab 39 18 16 03 03 00  cd 0c 00 00 c9 03 00 17  |..9.............|
+000002e0  41 04 8e c8 e8 42 7c 8a  01 c2 ff 01 cb 0b e1 20  |A....B|........ |
+000002f0  50 42 d4 3a 1b 34 ff 74  59 81 2f a2 0e 29 b2 f9  |PB.:.4.tY./..)..|
+00000300  47 cf 0d 08 97 cf aa 9f  fe f0 7f e8 f4 fd 3a fa  |G.............:.|
+00000310  a6 b6 47 32 d3 25 78 87  bf 77 cc 12 37 02 6a ad  |..G2.%x..w..7.j.|
+00000320  cf 2c 04 01 00 80 13 a1  95 17 7b 21 86 7f f2 02  |.,........{!....|
+00000330  9f ed 88 2d 1f 2c 38 96  bc fa 5a 39 85 4b 9f ff  |...-.,8...Z9.K..|
+00000340  5c 7a 02 1e 5f c9 4a 69  51 d3 83 34 9f dc 8c 39  |\z.._.JiQ..4...9|
+00000350  fe 81 76 fc c3 59 ff e2  a8 81 ca 6f f6 52 c9 44  |..v..Y.....o.R.D|
+00000360  a0 3f 5e 5e 92 20 db d9  2e 0b e3 ab 75 e7 79 f6  |.?^^. ......u.y.|
+00000370  b2 73 17 e1 94 1e 12 62  e9 b0 0f 04 e7 5d 83 ac  |.s.....b.....]..|
+00000380  71 ca a5 62 40 dd 69 b1  3f cf bb 3d c7 3e 51 6c  |q..b@.i.?..=.>Ql|
+00000390  11 f2 cf 39 f1 b5 72 bd  52 d4 3d 3c c0 90 34 c8  |...9..r.R.=<..4.|
+000003a0  4b 22 55 39 1c 2b 16 03  03 00 04 0e 00 00 00     |K"U9.+.........|
 >>> 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.|
 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 f2 20  58 ec f1 88 a6 26 79 9d  |....... X....&y.|
-00000070  2e 9b 02 b5 5e da e2 c1  c5 8d c8 93 6f 6d 07 4e  |....^.......om.N|
-00000080  fa dd ee cb b1 ae c7 3b  09 b2 cc 64 7a cd 98 91  |.......;...dz...|
-00000090  cb f8 3c 34 3b ed                                 |..<4;.|
+00000060  00 00 00 00 00 00 a2 6e  de ea 78 0c 4d 20 ad 1f  |.......n..x.M ..|
+00000070  1a f5 6b 15 09 f1 50 bb  cd 40 0e c7 d9 ed 7f e1  |..k...P..@......|
+00000080  4b bc d3 26 5d 89 b7 26  c5 6c 0e 59 6f 84 51 5d  |K..&]..&.l.Yo.Q]|
+00000090  2f 75 d8 0f 2e e8                                 |/u....|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 40 4c a1 8d bd 49  |..........@L...I|
-00000010  33 d3 72 fb 2f 23 7e 11  29 fc d2 ff 9b 67 30 c8  |3.r./#~.)....g0.|
-00000020  be c1 bc 51 6e 92 a5 f4  9d e3 b3 f9 d2 d4 c4 a5  |...Qn...........|
-00000030  83 23 90 b3 17 00 35 18  c5 ef 8b 18 a3 cf ed 9d  |.#....5.........|
-00000040  a9 52 c9 11 0a c9 55 c2  76 df 78                 |.R....U.v.x|
+00000000  14 03 03 00 01 01 16 03  03 00 40 dd d8 e7 63 89  |..........@...c.|
+00000010  8e cc 3e e0 df 6d 5a 42  b3 49 1b 66 e8 79 e9 f0  |..>..mZB.I.f.y..|
+00000020  8a c3 0e 5e d7 01 ac 04  81 6a e1 60 14 60 b9 a6  |...^.....j.`.`..|
+00000030  4c a5 46 43 74 df 30 1e  f8 74 77 4c b5 42 e5 25  |L.FCt.0..twL.B.%|
+00000040  81 9d b1 04 bc 02 46 bd  b1 55 d0                 |......F..U.|
 >>> 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 60 40 d0  bf 8f ef 05 2b 89 d7 bb  |.....`@.....+...|
-00000020  27 d0 1f b2 cf c3 ff 8e  be 69 16 a9 b3 03 e8 3c  |'........i.....<|
-00000030  30 1d 58 39 4a 15 03 03  00 30 00 00 00 00 00 00  |0.X9J....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 de 61 51 a1 3c fc  |...........aQ.<.|
-00000050  1c 7b e6 f2 7d e0 aa 80  2d 9c e9 22 09 5c dd 8a  |.{..}...-..".\..|
-00000060  55 cc c4 77 34 97 05 88  98 d3                    |U..w4.....|
+00000010  00 00 00 00 00 35 49 6d  a7 3f a1 39 5d 37 8d 2e  |.....5Im.?.9]7..|
+00000020  c5 1e 90 3b f9 60 58 d3  47 e3 db 73 8b aa 6c 9e  |...;.`X.G..s..l.|
+00000030  b5 82 55 09 62 15 03 03  00 30 00 00 00 00 00 00  |..U.b....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 71 b3 7b c7 d4 27  |..........q.{..'|
+00000050  f9 77 7f d0 80 25 1b 43  d0 0e 92 38 8c f3 2f 50  |.w...%.C...8../P|
+00000060  eb 96 22 fb e6 09 45 ec  7f 16                    |.."...E...|
index 73e34c0ce354b4006b36c3251adbfa07a688694d..ffdc3284b8458e7d523adf06877cf5b9a7c37582 100644 (file)
@@ -1,84 +1,79 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 51 02 00 00  4d 03 03 e8 ae 4c 97 41  |....Q...M....L.A|
-00000010  78 0f 08 84 d4 4a 80 6d  a2 e1 d0 67 40 8f 01 8b  |x....J.m...g@...|
-00000020  20 54 cb 28 16 52 04 fd  3c c2 84 20 30 96 f0 51  | T.(.R..<.. 0..Q|
-00000030  72 86 6a d8 47 b9 47 e3  a4 ad 97 77 a9 77 1a f9  |r.j.G.G....w.w..|
-00000040  ba 63 33 32 4f 43 09 1c  e1 bd 1b 3b 00 05 00 00  |.c32OC.....;....|
-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..|
-00000080  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000090  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-000000a0  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-000000b0  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000c0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000d0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000e0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000f0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-00000100  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-00000110  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000120  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000130  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000140  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000150  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000160  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000170  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000180  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000190  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-000001a0  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-000001b0  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001c0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001d0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001e0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001f0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-00000200  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-00000210  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000220  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000230  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000240  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000250  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000260  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000270  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000280  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000290  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-000002a0  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-000002b0  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002c0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002d0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002e0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002f0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-00000300  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 04 0e 00  |n8P)l...........|
-00000320  00 00                                             |..|
+00000000  16 03 03 00 51 02 00 00  4d 03 03 79 8f 56 ac 75  |....Q...M..y.V.u|
+00000010  4f a9 fc 2c b9 53 82 a6  b4 c8 0d 4e 50 9a 9e aa  |O..,.S.....NP...|
+00000020  8d ed 21 21 91 5d a2 cc  99 1b 68 20 0c e7 35 50  |..!!.]....h ..5P|
+00000030  67 02 70 2a 45 0d 6c 4c  46 df 75 dc 5f 6e 2f 79  |g.p*E.lLF.u._n/y|
+00000040  03 26 da 45 53 25 50 23  c0 85 3b 8c 00 05 00 00  |.&.ES%P#..;.....|
+00000050  05 ff 01 00 01 00 16 03  03 02 71 0b 00 02 6d 00  |..........q...m.|
+00000060  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000070  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000080  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000090  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+000000a0  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+000000b0  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000c0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000d0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000e0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000f0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+00000100  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+00000110  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000120  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000130  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000140  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000150  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000160  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000170  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000180  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000190  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+000001a0  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+000001b0  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001c0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001d0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001e0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001f0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+00000200  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+00000210  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f..@....xH.A0.|
+00000220  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000230  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000240  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000250  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H@.-.....|
+00000260  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000270  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000280  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000290  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+000002a0  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+000002b0  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002c0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
+000002d0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 6d 51 f3 7f f9  |...........mQ...|
-00000010  3e fb 75 82 41 36 83 e8  6a ee 2a 2e 25 90 67 4c  |>.u.A6..j.*.%.gL|
-00000020  8e 62 2f 30 81 17 e0 85  09 0c 2b b7 23 d7 b0 e2  |.b/0......+.#...|
-00000030  1d f7 3b d7 f5 a1 27 b6  ee 24 b6 1b cc 5b ea 66  |..;...'..$...[.f|
-00000040  0d 6a f4 e5 85 f9 da 43  b4 0e 86 85 e1 f5 aa be  |.j.....C........|
-00000050  c8 ce 39 4c 9c 86 00 08  c2 4b e2 c6 ec 2f f7 ce  |..9L.....K.../..|
-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 54 8c  7f 71 03 7c 98 e5 97 65  |.....$T..q.|...e|
-000000a0  51 13 b2 9d 4a b8 c9 c1  e6 11 1b 50 c8 1b c0 46  |Q...J......P...F|
-000000b0  a7 cb 13 97 92 a0 51 d4  a9 e5                    |......Q...|
+00000000  16 03 03 00 86 10 00 00  82 00 80 73 bd 73 65 92  |...........s.se.|
+00000010  86 23 41 14 79 7f d5 c1  10 ce 94 4d ad 9c c3 a9  |.#A.y......M....|
+00000020  87 b5 32 52 f8 6b 11 93  2d 9b 98 0b 8b 1d c0 f6  |..2R.k..-.......|
+00000030  53 17 6d c7 9c 2e ae c9  6f cc 99 23 38 37 1a 10  |S.m.....o..#87..|
+00000040  fe 05 0b b5 55 0a 14 e9  60 7d 70 26 98 e2 54 d9  |....U...`}p&..T.|
+00000050  65 cf 2e f4 53 5f 1d aa  3a f6 33 7b eb 4c 0e b3  |e...S_..:.3{.L..|
+00000060  ff 5a db 36 2a 47 f3 df  f9 fc f5 31 78 83 aa 6b  |.Z.6*G.....1x..k|
+00000070  52 b7 ba 1a 96 bc fa c1  a1 a9 bb 2b f5 38 89 00  |R..........+.8..|
+00000080  4d e5 78 13 4e a4 38 46  42 dc 16 14 03 03 00 01  |M.x.N.8FB.......|
+00000090  01 16 03 03 00 24 72 bd  b1 13 05 73 26 c0 0b ec  |.....$r....s&...|
+000000a0  e6 39 08 6a 2d 87 00 51  58 9d e3 8d da be 60 98  |.9.j-..QX.....`.|
+000000b0  0a ee 0c 96 13 f4 e5 30  90 85                    |.......0..|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 37 ca ae 55 79  |..........$7..Uy|
-00000010  e7 0a 70 55 1e d1 76 61  57 46 d2 c0 d0 ed 3d 70  |..pU..vaWF....=p|
-00000020  1f 02 f2 06 5b 3e 50 ec  13 4b 67 e2 7c bd 45     |....[>P..Kg.|.E|
+00000000  14 03 03 00 01 01 16 03  03 00 24 d4 ad ab a0 01  |..........$.....|
+00000010  1b 87 9c aa c4 27 08 b5  8c 4a 7f fc 03 df a6 d6  |.....'...J......|
+00000020  f8 6c d1 61 7c d3 1f 6d  18 c3 8d 88 5c 7b cf     |.l.a|..m....\{.|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1a c4 13 68  ec e0 38 a1 07 35 da d7  |.......h..8..5..|
-00000010  c4 6b f9 5c ed a7 8a cb  96 7a 22 7c ca a5 30 15  |.k.\.....z"|..0.|
-00000020  03 03 00 16 f7 a7 8d 41  b0 c1 4b 61 60 b0 b2 ed  |.......A..Ka`...|
-00000030  4a ab c3 54 d5 20 eb 67  b7 8f                    |J..T. .g..|
+00000000  17 03 03 00 1a 33 a8 7a  61 46 09 7b 64 e6 aa f8  |.....3.zaF.{d...|
+00000010  8a 43 d3 a9 0c e9 2e c0  89 7c 72 fb 75 50 50 15  |.C.......|r.uPP.|
+00000020  03 03 00 16 2b b9 b5 eb  f8 bd 53 20 ea 67 bc 47  |....+.....S .g.G|
+00000030  83 cf c5 6e f9 4f 9e 12  f5 1a                    |...n.O....|
index 826c9f0a579cdacfc83b3923bba61b4fb658dd02..e6187baa3f4d5ffa8425320f92348d4f5d725383 100644 (file)
@@ -1,19 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000000  16 03 01 00 85 01 00 00  81 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 22 c0 2f  |............."./|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 00 00                                 |......|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 12  00 00                    |..........|
 >>> Flow 2 (server to client)
-00000000  16 03 03 01 c6 02 00 01  c2 03 03 1b f6 69 c1 c2  |.............i..|
-00000010  36 77 72 32 69 95 c9 e7  db 9b 5d bd 59 ba 08 02  |6wr2i.....].Y...|
-00000020  1e 76 11 c4 8e 49 08 22  8e 8a 5a 20 44 ec d9 13  |.v...I."..Z D...|
-00000030  23 ad 05 45 48 29 00 c6  11 3d 5a 5c a1 ee 34 2b  |#..EH)...=Z\..4+|
-00000040  58 ef 34 5b 7e 42 08 84  23 66 56 ee c0 2f 00 01  |X.4[~B..#fV../..|
+00000000  16 03 03 01 c6 02 00 01  c2 03 03 5d d8 84 38 51  |...........]..8Q|
+00000010  c6 51 9e 6c d3 e0 b2 d7  81 2a 9b 1c 06 0b 11 c8  |.Q.l.....*......|
+00000020  54 90 f3 d1 66 83 7a 68  2f 65 8b 20 ac 8b 35 9a  |T...f.zh/e. ..5.|
+00000030  31 25 04 c9 89 31 27 80  8f 10 74 8e 3c 4f 20 bc  |1%...1'...t.<O .|
+00000040  3b 46 9d d0 91 f3 ca 7e  0e 59 b7 72 c0 2f 00 01  |;F.....~.Y.r./..|
 00000050  7a ff 01 00 01 00 00 0b  00 04 03 00 01 02 00 12  |z...............|
 00000060  01 69 01 67 00 75 00 a4  b9 09 90 b4 18 58 14 87  |.i.g.u.......X..|
 00000070  bb 13 a2 cc 67 70 0a 3c  35 98 04 f9 1b df b8 e3  |....gp.<5.......|
 00000190  91 bc f1 b5 40 be 1e 2e  e7 5c b4 74 27 ed 8f 9b  |....@....\.t'...|
 000001a0  02 e9 fa c2 4c ba a2 be  02 21 00 af 43 64 52 71  |....L....!..CdRq|
 000001b0  15 29 58 40 91 c7 08 16  96 03 a8 73 a5 65 a0 6c  |.)X@.......s.e.l|
-000001c0  b8 48 56 5a b6 29 83 64  6d 2a 9d 16 03 03 02 be  |.HVZ.).dm*......|
-000001d0  0b 00 02 ba 00 02 b7 00  02 b4 30 82 02 b0 30 82  |..........0...0.|
-000001e0  02 19 a0 03 02 01 02 02  09 00 85 b0 bb a4 8a 7f  |................|
-000001f0  b8 ca 30 0d 06 09 2a 86  48 86 f7 0d 01 01 05 05  |..0...*.H.......|
-00000200  00 30 45 31 0b 30 09 06  03 55 04 06 13 02 41 55  |.0E1.0...U....AU|
-00000210  31 13 30 11 06 03 55 04  08 13 0a 53 6f 6d 65 2d  |1.0...U....Some-|
-00000220  53 74 61 74 65 31 21 30  1f 06 03 55 04 0a 13 18  |State1!0...U....|
-00000230  49 6e 74 65 72 6e 65 74  20 57 69 64 67 69 74 73  |Internet Widgits|
-00000240  20 50 74 79 20 4c 74 64  30 1e 17 0d 31 30 30 34  | Pty Ltd0...1004|
-00000250  32 34 30 39 30 39 33 38  5a 17 0d 31 31 30 34 32  |24090938Z..11042|
-00000260  34 30 39 30 39 33 38 5a  30 45 31 0b 30 09 06 03  |4090938Z0E1.0...|
-00000270  55 04 06 13 02 41 55 31  13 30 11 06 03 55 04 08  |U....AU1.0...U..|
-00000280  13 0a 53 6f 6d 65 2d 53  74 61 74 65 31 21 30 1f  |..Some-State1!0.|
-00000290  06 03 55 04 0a 13 18 49  6e 74 65 72 6e 65 74 20  |..U....Internet |
-000002a0  57 69 64 67 69 74 73 20  50 74 79 20 4c 74 64 30  |Widgits Pty Ltd0|
-000002b0  81 9f 30 0d 06 09 2a 86  48 86 f7 0d 01 01 01 05  |..0...*.H.......|
-000002c0  00 03 81 8d 00 30 81 89  02 81 81 00 bb 79 d6 f5  |.....0.......y..|
-000002d0  17 b5 e5 bf 46 10 d0 dc  69 be e6 2b 07 43 5a d0  |....F...i..+.CZ.|
-000002e0  03 2d 8a 7a 43 85 b7 14  52 e7 a5 65 4c 2c 78 b8  |.-.zC...R..eL,x.|
-000002f0  23 8c b5 b4 82 e5 de 1f  95 3b 7e 62 a5 2c a5 33  |#........;~b.,.3|
-00000300  d6 fe 12 5c 7a 56 fc f5  06 bf fa 58 7b 26 3f b5  |...\zV.....X{&?.|
-00000310  cd 04 d3 d0 c9 21 96 4a  c7 f4 54 9f 5a bf ef 42  |.....!.J..T.Z..B|
-00000320  71 00 fe 18 99 07 7f 7e  88 7d 7d f1 04 39 c4 a2  |q......~.}}..9..|
-00000330  2e db 51 c9 7c e3 c0 4c  3b 32 66 01 cf af b1 1d  |..Q.|..L;2f.....|
-00000340  b8 71 9a 1d db db 89 6b  ae da 2d 79 02 03 01 00  |.q.....k..-y....|
-00000350  01 a3 81 a7 30 81 a4 30  1d 06 03 55 1d 0e 04 16  |....0..0...U....|
-00000360  04 14 b1 ad e2 85 5a cf  cb 28 db 69 ce 23 69 de  |......Z..(.i.#i.|
-00000370  d3 26 8e 18 88 39 30 75  06 03 55 1d 23 04 6e 30  |.&...90u..U.#.n0|
-00000380  6c 80 14 b1 ad e2 85 5a  cf cb 28 db 69 ce 23 69  |l......Z..(.i.#i|
-00000390  de d3 26 8e 18 88 39 a1  49 a4 47 30 45 31 0b 30  |..&...9.I.G0E1.0|
-000003a0  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
-000003b0  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
-000003c0  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
-000003d0  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
-000003e0  74 64 82 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0c 06  |td...........0..|
-000003f0  03 55 1d 13 04 05 30 03  01 01 ff 30 0d 06 09 2a  |.U....0....0...*|
-00000400  86 48 86 f7 0d 01 01 05  05 00 03 81 81 00 08 6c  |.H.............l|
-00000410  45 24 c7 6b b1 59 ab 0c  52 cc f2 b0 14 d7 87 9d  |E$.k.Y..R.......|
-00000420  7a 64 75 b5 5a 95 66 e4  c5 2b 8e ae 12 66 1f eb  |zdu.Z.f..+...f..|
-00000430  4f 38 b3 6e 60 d3 92 fd  f7 41 08 b5 25 13 b1 18  |O8.n`....A..%...|
-00000440  7a 24 fb 30 1d ba ed 98  b9 17 ec e7 d7 31 59 db  |z$.0.........1Y.|
-00000450  95 d3 1d 78 ea 50 56 5c  d5 82 5a 2d 5a 5f 33 c4  |...x.PV\..Z-Z_3.|
-00000460  b6 d8 c9 75 90 96 8c 0f  52 98 b5 cd 98 1f 89 20  |...u....R...... |
-00000470  5f f2 a0 1c a3 1b 96 94  dd a9 fd 57 e9 70 e8 26  |_..........W.p.&|
-00000480  6d 71 99 9b 26 6e 38 50  29 6c 90 a7 bd d9 16 03  |mq..&n8P)l......|
-00000490  03 00 cd 0c 00 00 c9 03  00 17 41 04 d7 61 5b 05  |..........A..a[.|
-000004a0  de 22 d3 3d 00 72 a5 be  0a c1 76 94 a1 34 41 6e  |.".=.r....v..4An|
-000004b0  55 f2 74 91 d2 6f 5c 47  87 c8 4b eb ab ab 10 b9  |U.t..o\G..K.....|
-000004c0  f9 0a bc 63 03 5f 90 5b  e3 6f e1 44 97 cc bf d2  |...c._.[.o.D....|
-000004d0  e8 0d f5 9c 2e 9d 07 2c  b2 00 90 0b 04 01 00 80  |.......,........|
-000004e0  67 3d c7 73 42 b9 b2 fd  4b dd 02 57 87 95 20 75  |g=.sB...K..W.. u|
-000004f0  da c1 e7 d3 33 09 01 5d  e9 32 d7 20 7f 92 a9 dd  |....3..].2. ....|
-00000500  bb 17 c5 ee f2 07 b2 04  1d 5e 1f c2 41 66 3f 14  |.........^..Af?.|
-00000510  90 cd 84 ac 49 46 04 3e  ce 89 7d 79 42 2a 8c 56  |....IF.>..}yB*.V|
-00000520  93 d3 9c 3b 57 38 9e 91  af 62 ad 86 40 29 3d 46  |...;W8...b..@)=F|
-00000530  c7 cc f4 3f a1 7d ee 53  3d 94 1c 85 b9 1d a9 5f  |...?.}.S=......_|
-00000540  10 8e ee 38 5e 98 5d 39  31 79 83 cd f9 02 a8 a9  |...8^.]91y......|
-00000550  b8 82 21 33 40 ed 27 54  a3 6e 64 cb e9 ce dd e1  |..!3@.'T.nd.....|
-00000560  16 03 03 00 04 0e 00 00  00                       |.........|
+000001c0  b8 48 56 5a b6 29 83 64  6d 2a 9d 16 03 03 02 71  |.HVZ.).dm*.....q|
+000001d0  0b 00 02 6d 00 02 6a 00  02 67 30 82 02 63 30 82  |...m..j..g0..c0.|
+000001e0  01 cc a0 03 02 01 02 02  09 00 a2 73 00 0c 81 00  |...........s....|
+000001f0  cb f3 30 0d 06 09 2a 86  48 86 f7 0d 01 01 0b 05  |..0...*.H.......|
+00000200  00 30 2b 31 17 30 15 06  03 55 04 0a 13 0e 47 6f  |.0+1.0...U....Go|
+00000210  6f 67 6c 65 20 54 45 53  54 49 4e 47 31 10 30 0e  |ogle TESTING1.0.|
+00000220  06 03 55 04 03 13 07 47  6f 20 52 6f 6f 74 30 1e  |..U....Go Root0.|
+00000230  17 0d 31 35 30 31 30 31  30 30 30 30 30 30 5a 17  |..150101000000Z.|
+00000240  0d 32 35 30 31 30 31 30  30 30 30 30 30 5a 30 26  |.250101000000Z0&|
+00000250  31 17 30 15 06 03 55 04  0a 13 0e 47 6f 6f 67 6c  |1.0...U....Googl|
+00000260  65 20 54 45 53 54 49 4e  47 31 0b 30 09 06 03 55  |e TESTING1.0...U|
+00000270  04 03 13 02 47 6f 30 81  9f 30 0d 06 09 2a 86 48  |....Go0..0...*.H|
+00000280  86 f7 0d 01 01 01 05 00  03 81 8d 00 30 81 89 02  |............0...|
+00000290  81 81 00 af 87 88 f6 20  1b 95 65 6c 14 ab 44 05  |....... ..el..D.|
+000002a0  af 3b 45 14 e3 b7 6d fd  00 63 4d 95 7f fe 6a 62  |.;E...m..cM...jb|
+000002b0  35 86 c0 4a f9 18 7c f6  aa 25 5e 7a 64 31 66 00  |5..J..|..%^zd1f.|
+000002c0  ba f4 8e 92 af c7 6b d8  76 d4 f3 5f 41 cb 6e 56  |......k.v.._A.nV|
+000002d0  15 97 1b 97 c1 3c 12 39  21 66 3d 2b 16 d1 bc db  |.....<.9!f=+....|
+000002e0  1c c0 a7 da b7 ca ad ba  da cb d5 21 50 ec de 8d  |...........!P...|
+000002f0  ab d1 6b 81 4b 89 02 f3  c4 be c1 6c 89 b1 44 84  |..k.K......l..D.|
+00000300  bd 21 d1 04 7d 9d 16 4d  f9 82 15 f6 ef fa d6 09  |.!..}..M........|
+00000310  47 f2 fb 02 03 01 00 01  a3 81 93 30 81 90 30 0e  |G..........0..0.|
+00000320  06 03 55 1d 0f 01 01 ff  04 04 03 02 05 a0 30 1d  |..U...........0.|
+00000330  06 03 55 1d 25 04 16 30  14 06 08 2b 06 01 05 05  |..U.%..0...+....|
+00000340  07 03 01 06 08 2b 06 01  05 05 07 03 02 30 0c 06  |.....+.......0..|
+00000350  03 55 1d 13 01 01 ff 04  02 30 00 30 19 06 03 55  |.U.......0.0...U|
+00000360  1d 0e 04 12 04 10 12 50  8d 89 6f 1b d1 dc 54 4d  |.......P..o...TM|
+00000370  6e cb 69 5e 06 f4 30 1b  06 03 55 1d 23 04 14 30  |n.i^..0...U.#..0|
+00000380  12 80 10 bf 3d b6 a9 66  f2 b8 40 cf ea b4 03 78  |....=..f..@....x|
+00000390  48 1a 41 30 19 06 03 55  1d 11 04 12 30 10 82 0e  |H.A0...U....0...|
+000003a0  65 78 61 6d 70 6c 65 2e  67 6f 6c 61 6e 67 30 0d  |example.golang0.|
+000003b0  06 09 2a 86 48 86 f7 0d  01 01 0b 05 00 03 81 81  |..*.H...........|
+000003c0  00 92 7c af 91 55 12 18  96 59 31 a6 48 40 d5 2d  |..|..U...Y1.H@.-|
+000003d0  d5 ee bb 02 a0 f5 c2 1e  7c 9b b3 30 7d 3c dc 76  |........|..0}<.v|
+000003e0  da 4f 3d c0 fa ae 2d 33  24 6b 03 7b 1b 67 59 11  |.O=...-3$k.{.gY.|
+000003f0  21 b5 11 bc 77 b9 d9 e0  6e a8 2d 2e 35 fa 64 5f  |!...w...n.-.5.d_|
+00000400  22 3e 63 10 6b be ff 14  86 6d 0d f0 15 31 a8 14  |">c.k....m...1..|
+00000410  38 1e 3b 84 87 2c cb 98  ed 51 76 b9 b1 4f dd db  |8.;..,...Qv..O..|
+00000420  9b 84 04 86 40 fa 51 dd  ba b4 8d eb e3 46 de 46  |....@.Q......F.F|
+00000430  b9 4f 86 c7 f9 a4 c2 41  34 ac cc f6 ea b0 ab 39  |.O.....A4......9|
+00000440  18 16 03 03 00 cd 0c 00  00 c9 03 00 17 41 04 1e  |.............A..|
+00000450  d1 1c 5c d3 00 41 84 cd  f7 e2 78 ad b5 7d 5b f2  |..\..A....x..}[.|
+00000460  23 5b 1a 18 44 3f 86 8e  3e 52 f2 4b b6 7d 84 b4  |#[..D?..>R.K.}..|
+00000470  1d 98 83 8f 2f 58 07 92  1f 58 2a 8d 8c e3 fa b7  |..../X...X*.....|
+00000480  aa 78 7e 33 9a 64 b9 b6  cb 78 94 be 2b c3 ac 04  |.x~3.d...x..+...|
+00000490  01 00 80 65 9f 42 e3 24  5c cd 18 aa 08 8e 6b bf  |...e.B.$\.....k.|
+000004a0  39 15 2a a3 e6 42 1c 9d  6b 34 39 a2 2c 58 f5 5f  |9.*..B..k49.,X._|
+000004b0  3e fb 2a 4c 01 2b e5 20  4e f5 69 77 c1 62 8f 68  |>.*L.+. N.iw.b.h|
+000004c0  be b4 c4 77 27 c9 4a 97  6d 18 7f 45 fd c9 9e 24  |...w'.J.m..E...$|
+000004d0  19 6b d9 00 c5 52 1a 34  a3 c9 cb eb 92 fc f6 48  |.k...R.4.......H|
+000004e0  3d 89 8a ff 82 be 55 c9  92 e2 24 86 b0 99 c6 e8  |=.....U...$.....|
+000004f0  a5 4c b7 bc 5a e5 f3 81  94 ee 15 47 e7 5e 8c 66  |.L..Z......G.^.f|
+00000500  32 72 7d 81 78 61 fe 25  98 dd 07 a2 92 4c eb ed  |2r}.xa.%.....L..|
+00000510  f1 a7 17 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.|
 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 60 0e  |.....(........`.|
-00000060  49 99 7a 9f 28 6e 46 03  a8 fd 0e b7 ed bb 9c ba  |I.z.(nF.........|
-00000070  07 9c 4d cc 26 2b c2 70  a0 26 38 a0 f2 a0        |..M.&+.p.&8...|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 f0 4f  |.....(.........O|
+00000060  fe 22 53 9e e1 61 f4 45  4e 41 ff 5e e4 63 25 f7  |."S..a.ENA.^.c%.|
+00000070  b2 f6 0a ea 89 75 7f d4  e7 3a cc e8 c2 2c        |.....u...:...,|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 d2 ef 8f f4 7b  |..........(....{|
-00000010  7a 9b c8 98 a4 36 f2 be  61 46 0e af f4 6f 63 71  |z....6..aF...ocq|
-00000020  6e bd 87 ea 1b f2 95 ad  36 7d a3 52 7f b2 b6 45  |n.......6}.R...E|
-00000030  3f 0b 62                                          |?.b|
+00000000  14 03 03 00 01 01 16 03  03 00 28 ad 49 0a 66 16  |..........(.I.f.|
+00000010  6d 64 42 c2 ab 38 bf 81  3d d9 14 13 d6 69 27 81  |mdB..8..=....i'.|
+00000020  ea 5c 53 fd 6c bf 81 6c  06 81 a5 67 f2 cd ed a3  |.\S.l..l...g....|
+00000030  d4 c2 08                                          |...|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 53 a1 85  |.............S..|
-00000010  ce 3c c1 64 39 80 fb db  67 ec 48 20 7f e9 82 f4  |.<.d9...g.H ....|
-00000020  2d 69 0a 15 03 03 00 1a  00 00 00 00 00 00 00 02  |-i..............|
-00000030  ab 78 11 1b 80 55 23 db  07 c5 7f c3 5e 19 d8 b3  |.x...U#.....^...|
-00000040  f8 c6                                             |..|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 5c ab e3  |.............\..|
+00000010  f9 61 72 9e 44 46 1a 05  e9 00 eb 5b e0 73 22 03  |.ar.DF.....[.s".|
+00000020  9f 90 f9 15 03 03 00 1a  00 00 00 00 00 00 00 02  |................|
+00000030  04 28 a4 9d 07 79 95 40  0f f0 eb b9 5d 97 bf 87  |.(...y.@....]...|
+00000040  4a b6                                             |J.|
index 20520f542d4923ecafe64f137fc53def751dbea0..10b7f52bce26fba7ad7b7d00403f20350866f8c8 100644 (file)
@@ -1,8 +1,8 @@
 >>> Flow 1 (client to server)
-00000000  16 03 00 00 2f 01 00 00  2b 03 00 10 71 68 59 99  |..../...+...qhY.|
-00000010  9c a6 e7 36 8b 0d 03 be  f5 42 ab 7c d0 3b 76 3e  |...6.....B.|.;v>|
-00000020  46 7c 6c a3 94 09 b7 1b  0e 42 27 00 00 04 00 0a  |F|l......B'.....|
-00000030  00 ff 01 00                                       |....|
+00000000  16 03 00 00 30 01 00 00  2c 03 00 50 32 2f f9 d5  |....0...,..P2/..|
+00000010  8f 83 ac 79 0e 0b e5 65  2c 87 79 01 7d 15 73 00  |...y...e,.y.}.s.|
+00000020  46 7c dc c6 6d 70 0b f3  d2 dc de 00 00 04 00 0a  |F|..mp..........|
+00000030  00 ff 02 01 00                                    |.....|
 >>> Flow 2 (server to client)
 00000000  16 03 00 00 31 02 00 00  2d 03 00 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 00 00  |..A4......9.....|
 000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 00 00 84 10 00 00  80 1b 62 18 c8 60 0b f7  |..........b..`..|
-00000010  4a b8 ec 98 56 eb aa 4b  d9 05 c0 f1 be b9 a5 28  |J...V..K.......(|
-00000020  62 e8 3e 25 08 9f 28 dd  08 1f 04 80 5f 10 81 cf  |b.>%..(....._...|
-00000030  aa 2f 55 cd f1 0f ec 5b  90 0a 1f 49 bc a3 96 38  |./U....[...I...8|
-00000040  c7 32 b6 0a da b3 a5 7a  76 28 82 19 30 f4 6b ae  |.2.....zv(..0.k.|
-00000050  fb 81 cc b4 ad 92 f8 c6  20 da 27 89 45 f4 43 c2  |........ .'.E.C.|
-00000060  16 7e de 29 03 dc 90 dd  3a 23 58 4c 35 be 11 a5  |.~.)....:#XL5...|
-00000070  52 18 79 13 e6 b3 2d e6  8e f5 76 60 0c c1 92 bb  |R.y...-...v`....|
-00000080  07 67 c5 24 12 1b aa d6  53 14 03 00 00 01 01 16  |.g.$....S.......|
-00000090  03 00 00 40 5f 64 da b6  24 19 07 44 32 85 f3 c0  |...@_d..$..D2...|
-000000a0  9b c6 2c ad b1 d1 0f 4b  52 20 2f ea 6f 15 80 44  |..,....KR /.o..D|
-000000b0  78 34 44 02 67 e0 2e b4  b8 df 7b 3f 21 dd 66 9b  |x4D.g.....{?!.f.|
-000000c0  e7 5f 71 ff 5f 30 fb 5b  5a 19 f0 24 f8 21 bc 7c  |._q._0.[Z..$.!.||
-000000d0  00 e1 1f e8                                       |....|
+00000000  16 03 00 00 84 10 00 00  80 48 96 89 e9 d2 e6 c6  |.........H......|
+00000010  eb 9d f8 46 dd c7 d8 01  95 57 76 1a 59 1c 79 21  |...F.....Wv.Y.y!|
+00000020  94 0b 83 b2 c9 5e c1 5f  4f 12 00 10 63 12 d3 f9  |.....^._O...c...|
+00000030  ae ae 31 18 fa b4 33 37  eb b9 23 15 55 7e cf 62  |..1...37..#.U~.b|
+00000040  20 a7 cb eb 69 35 e0 35  32 e4 0a 4c c0 33 e9 7d  | ...i5.52..L.3.}|
+00000050  f2 a8 4b e2 fe 90 62 7a  09 df c5 46 03 0c 52 7a  |..K...bz...F..Rz|
+00000060  fb 96 dd fd 55 aa e5 be  3c 35 65 03 be e1 51 0f  |....U...<5e...Q.|
+00000070  7b b3 05 6b e9 af 9b 0e  e4 ea d9 34 69 a5 c2 9a  |{..k.......4i...|
+00000080  71 a8 cc 0a 94 ef 91 14  88 14 03 00 00 01 01 16  |q...............|
+00000090  03 00 00 40 0c 34 26 4c  cf f0 d4 a0 08 b9 b7 6b  |...@.4&L.......k|
+000000a0  0a 69 55 48 91 2c 92 4c  9b e7 66 d0 b8 da 2d e7  |.iUH.,.L..f...-.|
+000000b0  89 ca f5 a4 3d 11 ff 87  22 07 c0 ed 72 9c ad 19  |....=..."...r...|
+000000c0  7d 63 2b 67 43 e3 33 76  a1 ac 69 77 55 bb 60 ba  |}c+gC.3v..iwU.`.|
+000000d0  57 00 4e 2a                                       |W.N*|
 >>> Flow 4 (server to client)
-00000000  14 03 00 00 01 01 16 03  00 00 40 48 01 fc 08 a0  |..........@H....|
-00000010  fa 0e 63 58 25 18 06 3c  54 5c 60 ce 35 f6 ec b8  |..cX%..<T\`.5...|
-00000020  ed f8 97 c7 b0 5f 96 6b  d1 10 53 e9 23 20 44 56  |....._.k..S.# DV|
-00000030  d7 ee 11 e1 6f b7 1e fb  33 94 7f f0 78 f5 2e 02  |....o...3...x...|
-00000040  37 7a 43 cf e7 c7 52 b3  c6 8d 8e 17 03 00 00 18  |7zC...R.........|
-00000050  f7 3c 05 79 4b 55 8c d7  2c 50 82 f0 61 34 f6 c7  |.<.yKU..,P..a4..|
-00000060  f3 71 e1 76 1d f0 65 b6  17 03 00 00 28 50 ce 6c  |.q.v..e.....(P.l|
-00000070  96 97 70 88 b7 3c 74 a9  cb a3 0e ae 3a 7f 85 99  |..p..<t.....:...|
-00000080  58 36 10 7f 1a e8 f8 7d  83 75 24 7e b1 6a 8e b0  |X6.....}.u$~.j..|
-00000090  f1 cc 06 19 f7 15 03 00  00 18 2c 1d 87 1d ce 08  |..........,.....|
-000000a0  8f 10 09 6e bd fc ad e0  1d a7 47 d5 b9 8f 3e b8  |...n......G...>.|
-000000b0  b3 fa                                             |..|
+00000000  14 03 00 00 01 01 16 03  00 00 40 dd e1 34 c5 4a  |..........@..4.J|
+00000010  96 76 81 49 df 1b 3d 48  cc 6c b0 3b ee 77 a9 62  |.v.I..=H.l.;.w.b|
+00000020  91 b3 16 b0 e1 79 4b 2a  95 d8 54 98 7b 5e ac 0f  |.....yK*..T.{^..|
+00000030  07 3b 06 36 e1 38 dc 75  6a af f7 ce a4 b2 3f 9e  |.;.6.8.uj.....?.|
+00000040  36 b1 44 ce e9 6c 34 ba  ce 97 02 17 03 00 00 18  |6.D..l4.........|
+00000050  5b be 71 2f a1 15 2f e9  9b 83 8e f1 9b e7 5b 4a  |[.q/../.......[J|
+00000060  a1 85 13 03 c0 f2 30 0c  17 03 00 00 28 2c d9 9e  |......0.....(,..|
+00000070  f4 d2 70 2a 37 76 66 e7  f4 5c c7 55 be d8 82 49  |..p*7vf..\.U...I|
+00000080  77 e0 4f 0f 87 4b c0 b1  f3 d2 a3 63 df 62 bc ee  |w.O..K.....c.b..|
+00000090  5c c2 50 2a 96 15 03 00  00 18 8b 0a 68 8a d8 64  |\.P*........h..d|
+000000a0  4e 3f f9 ee c6 b2 21 51  03 10 6b 73 3b 8c a4 bb  |N?....!Q..ks;...|
+000000b0  6d f2                                             |m.|
index e0fe95658dac3653b0a02707289e1b05436cb507..e73381950eb0fe73cefb5316772dda595673ee46 100644 (file)
@@ -1,8 +1,8 @@
 >>> Flow 1 (client to server)
-00000000  16 03 00 00 2f 01 00 00  2b 03 00 37 cd 49 a6 9f  |..../...+..7.I..|
-00000010  e9 19 6a 39 cd 75 ce 6c  f1 1b 96 d3 d4 f0 33 0c  |..j9.u.l......3.|
-00000020  8f 53 b2 06 c4 0e 39 86  e3 98 7e 00 00 04 00 2f  |.S....9...~..../|
-00000030  00 ff 01 00                                       |....|
+00000000  16 03 00 00 30 01 00 00  2c 03 00 36 b0 f3 52 13  |....0...,..6..R.|
+00000010  00 17 16 8f 6e 44 24 06  84 05 5b 03 e6 8a 55 ee  |....nD$...[...U.|
+00000020  75 9c a8 77 9e e0 7b 15  f9 60 6e 00 00 04 00 2f  |u..w..{..`n..../|
+00000030  00 ff 02 01 00                                    |.....|
 >>> Flow 2 (server to client)
 00000000  16 03 00 00 31 02 00 00  2d 03 00 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 00 00  |..A4......9.....|
 000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 00 00 84 10 00 00  80 4d 3f 93 aa 84 d8 ad  |.........M?.....|
-00000010  93 2c 63 02 66 2f 96 88  b8 5c 09 1e 63 e2 e5 96  |.,c.f/...\..c...|
-00000020  26 d8 07 14 86 26 62 f4  0c 04 68 1c bf bb b1 53  |&....&b...h....S|
-00000030  97 96 43 59 4a 57 65 12  88 45 34 2b 86 2b 05 aa  |..CYJWe..E4+.+..|
-00000040  9b 2b b9 aa 13 30 5c 91  c0 9f 03 8a 96 61 dd 87  |.+...0\......a..|
-00000050  ae e3 ad 6a 7b 8a 18 23  67 c9 df ad f2 47 eb 8b  |...j{..#g....G..|
-00000060  7d 24 95 47 f1 4e b5 c6  15 b4 12 2a 42 df b3 99  |}$.G.N.....*B...|
-00000070  d1 b8 60 ce 6a cf 98 c1  13 a1 68 e6 92 ee 92 a2  |..`.j.....h.....|
-00000080  1d 2f 63 66 f3 b9 1b fc  33 14 03 00 00 01 01 16  |./cf....3.......|
-00000090  03 00 00 40 75 48 68 7d  8f f5 5a c0 cb 90 a5 9e  |...@uHh}..Z.....|
-000000a0  94 bb eb 61 b5 36 aa ce  09 7a 11 ba 22 56 2a d7  |...a.6...z.."V*.|
-000000b0  91 a3 99 73 5b c5 b2 b7  b9 92 56 c6 cb fe 13 73  |...s[.....V....s|
-000000c0  28 30 03 26 62 63 7e 8a  d2 58 c8 e7 52 03 26 67  |(0.&bc~..X..R.&g|
-000000d0  48 21 4f 21                                       |H!O!|
+00000000  16 03 00 00 84 10 00 00  80 2d 0b b1 1c 96 72 65  |.........-....re|
+00000010  e5 3b 5b 48 35 91 b8 2e  18 b5 6c 36 a4 91 10 0e  |.;[H5.....l6....|
+00000020  15 63 de fb 7e ea 44 cd  2e 2f 37 2c 88 96 30 d4  |.c..~.D../7,..0.|
+00000030  07 ff 02 9b af 84 2c 43  6c 3a 1f 75 17 4c 5e 8b  |......,Cl:.u.L^.|
+00000040  4a d9 df 68 fe ad 72 c9  0c f7 a5 0c a1 70 8b 9f  |J..h..r......p..|
+00000050  e7 8e 1d 32 61 8e 80 e5  3a 3a 61 ea 22 1a 67 e5  |...2a...::a.".g.|
+00000060  06 6a 5e 0c 65 bd c7 32  9c 13 c1 53 ad 8e f1 be  |.j^.e..2...S....|
+00000070  4d 6c 53 89 8f 9c 49 d2  85 58 04 b5 e8 53 b4 82  |MlS...I..X...S..|
+00000080  84 46 9d 70 fa 0a 34 15  1d 14 03 00 00 01 01 16  |.F.p..4.........|
+00000090  03 00 00 40 71 c7 4b ef  6b 7a f4 a2 29 dd c0 4b  |...@q.K.kz..)..K|
+000000a0  ef 04 7d ea 1c 31 16 38  ae 85 f9 89 db 2f a8 04  |..}..1.8...../..|
+000000b0  ad 61 b7 33 73 8c 31 9b  72 5a f6 8b 10 71 0c af  |.a.3s.1.rZ...q..|
+000000c0  99 89 14 63 b8 19 f8 0e  2c 0f 14 c6 d6 0a bd 4f  |...c....,......O|
+000000d0  96 59 0d 60                                       |.Y.`|
 >>> Flow 4 (server to client)
-00000000  14 03 00 00 01 01 16 03  00 00 40 84 8f 6e 80 35  |..........@..n.5|
-00000010  57 73 64 ef 29 bb 25 ff  5d 9d c7 55 38 b7 18 b3  |Wsd.).%.]..U8...|
-00000020  13 d1 ac 20 e0 1e f8 48  47 7a 40 2d bc a7 f2 af  |... ...HGz@-....|
-00000030  ed a6 26 48 f4 51 b4 b6  56 60 9b c3 d9 43 00 95  |..&H.Q..V`...C..|
-00000040  86 be 6c 4e 49 6b f9 10  99 51 22 17 03 00 00 20  |..lNIk...Q".... |
-00000050  d4 7e dc 50 7b c2 26 ee  79 09 84 9f d7 e0 52 b1  |.~.P{.&.y.....R.|
-00000060  e8 9c 92 30 b7 34 06 c6  e5 86 57 a1 fb 8d 06 d6  |...0.4....W.....|
-00000070  17 03 00 00 30 93 0a 3d  64 26 3d a2 74 bc 8f d1  |....0..=d&=.t...|
-00000080  16 38 d0 6b 62 eb 82 b0  9a 50 68 aa 7e f7 45 32  |.8.kb....Ph.~.E2|
-00000090  43 cb 84 2d 95 39 6c bc  c8 a0 2d aa ea fe f5 84  |C..-.9l...-.....|
-000000a0  c8 e4 8b 93 a1 15 03 00  00 20 03 7b 3e 43 1d 0a  |......... .{>C..|
-000000b0  9b 9b e3 17 0f de be 75  e5 6e 2f 5b e8 8d a8 68  |.......u.n/[...h|
-000000c0  4e f0 82 49 00 dd b6 95  b4 22                    |N..I....."|
+00000000  14 03 00 00 01 01 16 03  00 00 40 28 76 de 29 3b  |..........@(v.);|
+00000010  48 77 56 f1 e5 97 21 20  88 9c 7d 5e 02 3d bb c9  |HwV...! ..}^.=..|
+00000020  2f b1 ce 2e 65 ac 53 ea  a2 06 0e fb cf 53 28 1d  |/...e.S......S(.|
+00000030  df b3 24 48 52 7a 28 d6  9e 50 83 64 da 34 c1 f4  |..$HRz(..P.d.4..|
+00000040  c9 bf ec 42 33 c4 8a 6f  89 aa 1c 17 03 00 00 20  |...B3..o....... |
+00000050  f2 af bb 38 4f 37 58 0e  c4 2b 28 45 01 45 89 e9  |...8O7X..+(E.E..|
+00000060  31 5a 6d 8d 4d 1b 49 bd  7d 87 8a 62 e6 c8 03 43  |1Zm.M.I.}..b...C|
+00000070  17 03 00 00 30 60 ec e4  6f ec 88 33 d8 89 49 73  |....0`..o..3..Is|
+00000080  3a aa 67 ab 45 9f de c7  3f 0e 39 3d 9a 30 99 9c  |:.g.E...?.9=.0..|
+00000090  2d 10 5f f0 7d 70 10 d5  8e ca 18 91 25 e8 9d d1  |-._.}p......%...|
+000000a0  36 b0 a7 90 9b 15 03 00  00 20 63 e9 92 98 7d b1  |6........ c...}.|
+000000b0  9a 88 07 37 b2 27 99 95  b9 16 17 74 c2 42 9c dc  |...7.'.....t.B..|
+000000c0  80 32 de f4 f6 87 cb f1  87 d8                    |.2........|
index 39124c67ef17599532481192643d242c9fd89a5e..dce3ebe9cd3776fa1933882bb6d78e2bc7ca47ad 100644 (file)
@@ -1,8 +1,8 @@
 >>> Flow 1 (client to server)
-00000000  16 03 00 00 2f 01 00 00  2b 03 00 a7 1d 3d ed 0f  |..../...+....=..|
-00000010  2c 7b 1f f1 c8 1c a9 17  ce 69 e2 73 a2 07 d2 91  |,{.......i.s....|
-00000020  e9 27 fa 70 11 6f 18 6d  2a 25 f1 00 00 04 00 05  |.'.p.o.m*%......|
-00000030  00 ff 01 00                                       |....|
+00000000  16 03 00 00 30 01 00 00  2c 03 00 3c 64 40 96 81  |....0...,..<d@..|
+00000010  b4 90 3d a5 bb 90 8a ba  39 73 4c cd 2d f9 4c 12  |..=.....9sL.-.L.|
+00000020  4c 6e d6 09 43 e3 eb 07  2e 52 1a 00 00 04 00 05  |Ln..C....R......|
+00000030  00 ff 02 01 00                                    |.....|
 >>> Flow 2 (server to client)
 00000000  16 03 00 00 31 02 00 00  2d 03 00 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 00 00  |..A4......9.....|
 000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 00 00 84 10 00 00  80 25 85 a3 22 29 e4 fb  |.........%..")..|
-00000010  53 b9 a3 6b ed 70 2b 35  7f db 08 35 b8 4c 95 cd  |S..k.p+5...5.L..|
-00000020  00 ec 5e a1 2e ba e9 ac  a6 d4 ef ca 74 a0 12 1b  |..^.........t...|
-00000030  a7 ec 76 22 2c 63 71 1a  3a 50 94 ce 96 c4 d7 76  |..v",cq.:P.....v|
-00000040  1f 47 58 c7 57 98 af ea  7e 57 05 68 d3 f9 87 02  |.GX.W...~W.h....|
-00000050  35 72 35 66 08 b4 cf 48  24 15 92 d5 ba 46 8d 60  |5r5f...H$....F.`|
-00000060  5a 53 0b e4 9b 53 44 55  dc 77 d1 e4 e0 25 51 f6  |ZS...SDU.w...%Q.|
-00000070  f1 7c 96 0b 32 d4 8c 04  d3 3d e6 70 c7 d6 60 a7  |.|..2....=.p..`.|
-00000080  ae 69 22 69 41 1a 8d 12  67 14 03 00 00 01 01 16  |.i"iA...g.......|
-00000090  03 00 00 3c 32 dd 86 fd  5b 53 74 ea 01 45 5b 9e  |...<2...[St..E[.|
-000000a0  32 d0 9d 27 e8 ce 4c d5  a1 c2 d3 2e 0a e9 e5 d2  |2..'..L.........|
-000000b0  04 8c 77 a3 ff e9 8b 02  14 16 af 54 db ec c4 98  |..w........T....|
-000000c0  72 50 f7 65 fa eb ac 11  07 81 d7 fa 4e 18 34 bc  |rP.e........N.4.|
+00000000  16 03 00 00 84 10 00 00  80 00 e0 40 dd e4 0f 54  |...........@...T|
+00000010  40 66 62 06 72 2a 7a 06  2d a9 0f 16 3b 5c 63 9b  |@fb.r*z.-...;\c.|
+00000020  95 82 9c d4 95 57 c0 37  d1 30 6a 33 e1 5a ec 93  |.....W.7.0j3.Z..|
+00000030  12 ec 2a 94 c6 9c b3 6c  a3 4f ef cd f1 80 25 a7  |..*....l.O....%.|
+00000040  54 ca 6a 6e b9 80 0b fc  f1 e9 60 a0 f5 33 24 3b  |T.jn......`..3$;|
+00000050  13 04 9a f1 8a 37 cd 11  cf 95 ae 71 ba 73 8e 00  |.....7.....q.s..|
+00000060  86 17 6a 3b d5 9e a9 04  87 fd 62 ed 4c b5 01 55  |..j;......b.L..U|
+00000070  65 a2 fb e8 1d 86 a5 58  2a ad e7 fd d3 44 2f 7d  |e......X*....D/}|
+00000080  25 b7 3b c7 75 39 5c 45  f6 14 03 00 00 01 01 16  |%.;.u9\E........|
+00000090  03 00 00 3c e6 58 15 b2  fb 0d 44 ed 43 d5 ff a8  |...<.X....D.C...|
+000000a0  41 25 83 41 46 da f6 8e  70 34 39 c6 6c 2c ea 1b  |A%.AF...p49.l,..|
+000000b0  2a 02 5c 4b e4 87 58 33  6c d0 22 2e ce 85 df 31  |*.\K..X3l."....1|
+000000c0  0d 71 4c 1a f9 9c 64 d7  87 53 eb c9 1a 0a 16 dc  |.qL...d..S......|
 >>> Flow 4 (server to client)
-00000000  14 03 00 00 01 01 16 03  00 00 3c 29 af 2c 96 3a  |..........<).,.:|
-00000010  be a0 91 a8 e4 66 6b 30  ba e2 80 fc a2 8a 09 b4  |.....fk0........|
-00000020  28 14 3b 36 c2 3b 3e 88  e2 10 da 93 af 71 9a 06  |(.;6.;>......q..|
-00000030  1c 8d 97 04 05 ec e2 69  cf 28 20 0f ec 4c a7 f3  |.......i.( ..L..|
-00000040  18 4e 6b 5b 88 9c a9 17  03 00 00 21 5e 0b b4 2d  |.Nk[.......!^..-|
-00000050  a6 b5 0b 3a 86 de 8a e7  87 f3 4c f6 74 7e 0d 16  |...:......L.t~..|
-00000060  9b fc 0c 42 6b f4 9e 15  8b 6a c5 97 88 15 03 00  |...Bk....j......|
-00000070  00 16 f0 a4 e2 16 bf 81  05 ad 1d f5 1c 89 d9 ab  |................|
-00000080  48 23 ab 96 ea 92 aa cd                           |H#......|
+00000000  14 03 00 00 01 01 16 03  00 00 3c 17 a2 5b 4a 06  |..........<..[J.|
+00000010  63 6a 4b f9 ef 66 ed 31  f6 87 75 20 8b 08 8d 5d  |cjK..f.1..u ...]|
+00000020  0f 72 87 dd 8d db 99 d5  06 42 2b a3 84 77 35 f2  |.r.......B+..w5.|
+00000030  1d 11 ae 0b 0c df ed 10  6e 23 27 93 29 65 25 f6  |........n#'.)e%.|
+00000040  60 b9 76 c8 95 2b 0c 17  03 00 00 21 df 08 e8 1f  |`.v..+.....!....|
+00000050  2f ea 5a 61 d6 d4 4a c0  c1 b5 59 bc e1 89 6e 88  |/.Za..J...Y...n.|
+00000060  bb 8d 16 db 64 87 31 6c  2d d6 c7 d2 ed 15 03 00  |....d.1l-.......|
+00000070  00 16 a9 53 32 af 7a a4  88 02 93 6b aa 95 84 4f  |...S2.z....k...O|
+00000080  17 5a 97 93 67 87 3b 07                           |.Z..g.;.|
index f81ffc28c0e585f3c3e4882139ac4f2c079ee4ce..9314b9092411deb2c53e58d83ea4d34bd0effb8a 100644 (file)
@@ -1,13 +1,11 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 7d 01 00 00  79 03 01 65 14 3f 40 e4  |....}...y..e.?@.|
-00000010  2f 74 65 7e d0 c8 87 03  59 61 9d c3 84 5e c9 62  |/te~....Ya...^.b|
-00000020  e6 46 b8 0c 4a 5e 3f 33  43 a5 dd 00 00 04 c0 0a  |.F..J^?3C.......|
-00000030  00 ff 02 01 00 00 4b 00  0b 00 04 03 00 01 02 00  |......K.........|
-00000040  0a 00 3a 00 38 00 0e 00  0d 00 19 00 1c 00 0b 00  |..:.8...........|
-00000050  0c 00 1b 00 18 00 09 00  0a 00 1a 00 16 00 17 00  |................|
-00000060  08 00 06 00 07 00 14 00  15 00 04 00 05 00 12 00  |................|
-00000070  13 00 01 00 02 00 03 00  0f 00 10 00 11 00 0f 00  |................|
-00000080  01 01                                             |..|
+00000000  16 03 01 00 5f 01 00 00  5b 03 01 ad 87 94 6b 8a  |...._...[.....k.|
+00000010  38 9e 70 d6 94 8a 73 a9  39 d8 d7 25 ab 47 92 4c  |8.p...s.9..%.G.L|
+00000020  b1 20 8e 4d f3 7b cd 84  5e 13 c1 00 00 04 c0 0a  |. .M.{..^.......|
+00000030  00 ff 02 01 00 00 2d 00  0b 00 04 03 00 01 02 00  |......-.........|
+00000040  0a 00 1c 00 1a 00 17 00  19 00 1c 00 1b 00 18 00  |................|
+00000050  1a 00 16 00 0e 00 0d 00  0b 00 0c 00 09 00 0a 00  |................|
+00000060  0f 00 01 01                                       |....|
 >>> Flow 2 (server to client)
 00000000  16 03 01 00 31 02 00 00  2d 03 01 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 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 01 3e  |A.Vk.Z...0...B.>|
-000002a0  79 81 6e 89 cd 3e 3f ec  e4 b5 75 17 28 ee fb 09  |y.n..>?...u.(...|
-000002b0  21 19 6f 3c e6 ca 1e f2  18 b6 47 f8 37 05 1c 85  |!.o<......G.7...|
-000002c0  0f a4 b8 6b 40 04 50 77  e3 05 9b 24 b8 93 e8 4d  |...k@.Pw...$...M|
-000002d0  ef 30 cd 51 90 58 a2 49  71 b3 3f b9 46 ab a9 72  |.0.Q.X.Iq.?.F..r|
-000002e0  02 42 01 58 ef 20 c1 0a  33 f8 fd 50 9e 65 f5 ef  |.B.X. ..3..P.e..|
-000002f0  f4 91 49 2d d2 de 66 2b  97 69 7d b1 d0 ef d6 91  |..I-..f+.i}.....|
-00000300  0f fc 57 2b 73 b9 49 01  33 d2 1b 5b 9a 2c 51 35  |..W+s.I.3..[.,Q5|
-00000310  0e eb 38 53 fa 20 07 84  52 b3 43 24 09 5a 32 c0  |..8S. ..R.C$.Z2.|
-00000320  32 17 34 6c 16 03 01 00  04 0e 00 00 00           |2.4l.........|
+00000290  41 03 56 6b dc 5a 89 00  8b 30 81 88 02 42 00 8b  |A.Vk.Z...0...B..|
+000002a0  48 d5 a3 a0 35 5c 31 f5  0b e8 72 7c 87 31 79 af  |H...5\1...r|.1y.|
+000002b0  7f 12 93 9a f9 df d5 44  bf 08 5a 6b 1c 68 dd 73  |.......D..Zk.h.s|
+000002c0  67 0f 32 41 45 53 bf 74  cf 91 54 e7 7a 88 41 7a  |g.2AES.t..T.z.Az|
+000002d0  15 ea 3d e3 b8 93 c0 3f  24 4c fb ee 25 f1 20 80  |..=....?$L..%. .|
+000002e0  02 42 01 ab 97 5f 8b 8d  22 71 f9 f5 a3 59 69 42  |.B..._.."q...YiB|
+000002f0  06 bd 12 f5 61 53 cb c8  a1 b4 90 87 12 94 9b f8  |....aS..........|
+00000300  b3 1d 34 d9 cd 64 20 9c  92 ec b5 72 35 01 44 3a  |..4..d ....r5.D:|
+00000310  86 e4 54 46 0d 74 1d 4e  d8 41 16 eb ac c3 8a 2f  |..TF.t.N.A...../|
+00000320  20 11 ad bc 16 03 01 00  04 0e 00 00 00           | ............|
 >>> Flow 3 (client to server)
-00000000  16 03 01 00 46 10 00 00  42 41 04 31 74 f8 f6 18  |....F...BA.1t...|
-00000010  55 6a 9b 3b 78 0a 0e f0  c9 91 aa 8e 77 39 0a 88  |Uj.;x.......w9..|
-00000020  a4 d4 f6 04 9d de 89 18  b6 50 12 72 26 9c 8f e1  |.........P.r&...|
-00000030  f0 b2 e6 df ce 3b 46 be  e9 2a 9a e3 7f d1 d5 92  |.....;F..*......|
-00000040  ff e3 ae 0a 2d a1 3b 07  f6 04 59 14 03 01 00 01  |....-.;...Y.....|
-00000050  01 16 03 01 00 30 02 4f  df 41 30 97 6f f7 18 ca  |.....0.O.A0.o...|
-00000060  05 35 17 a1 a2 a5 71 61  b1 d8 dd 9a c6 f3 54 53  |.5....qa......TS|
-00000070  84 f6 fb 93 1e 0e 9d e7  fe 35 85 9e 73 d0 2e a1  |.........5..s...|
-00000080  a7 63 d9 40 c6 ac                                 |.c.@..|
+00000000  16 03 01 00 46 10 00 00  42 41 04 38 ca 59 61 cd  |....F...BA.8.Ya.|
+00000010  17 4a cf a8 0b 81 c6 b7  7f 52 dd 95 d7 57 9d 24  |.J.......R...W.$|
+00000020  bb b1 02 af 57 ee b9 f9  c5 a0 c3 20 44 e1 9a e4  |....W...... D...|
+00000030  83 64 7d a1 fa 9d 2e 3b  5e be 0f af ed 96 f3 09  |.d}....;^.......|
+00000040  62 a2 22 21 72 f8 84 89  8a fd 10 14 03 01 00 01  |b."!r...........|
+00000050  01 16 03 01 00 30 bd e6  23 e0 32 b8 4c ef ce 9e  |.....0..#.2.L...|
+00000060  22 a5 77 2c f1 7e 2f 8d  8b 9e a5 92 42 f9 0f 02  |".w,.~/.....B...|
+00000070  eb 2e 94 f1 6d a3 24 3f  c0 ae bb c0 c4 99 08 51  |....m.$?.......Q|
+00000080  47 28 8b 4e f9 02                                 |G(.N..|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 07 7e 4e 9c 19  |..........0.~N..|
-00000010  f0 35 cd 02 b7 a6 0a 1a  b1 a8 11 a3 f9 b1 35 7b  |.5............5{|
-00000020  96 7f e6 e1 00 c6 6d 9e  e6 8a bb a2 b8 bd a3 9d  |......m.........|
-00000030  05 22 1b f1 f5 28 4a 00  6e f1 71 17 03 01 00 20  |."...(J.n.q.... |
-00000040  ad c7 4c dc f4 81 1a 39  3d 86 5e 8e f5 0d a3 33  |..L....9=.^....3|
-00000050  88 32 e7 be 8b 6a 8d 44  29 7b 47 fd e5 33 01 1e  |.2...j.D){G..3..|
-00000060  17 03 01 00 30 61 47 ee  ae 89 25 ac 85 3b 8a 84  |....0aG...%..;..|
-00000070  47 61 ea 3e 4c 70 57 07  d6 f1 1c 21 cb 44 7e de  |Ga.>LpW....!.D~.|
-00000080  b5 01 9e fb fe ad bc be  74 c0 65 a0 6b c1 0c 8c  |........t.e.k...|
-00000090  2b 00 24 c6 b7 15 03 01  00 20 b7 8b 6b e5 77 ab  |+.$...... ..k.w.|
-000000a0  f6 50 9e 88 4d 56 a8 25  8d 02 db cb 68 8b 3f 62  |.P..MV.%....h.?b|
-000000b0  be aa 02 24 75 b1 e5 4b  18 c9                    |...$u..K..|
+00000000  14 03 01 00 01 01 16 03  01 00 30 11 a9 f0 95 27  |..........0....'|
+00000010  ac 0a b7 8e 0d 42 0a 2a  f8 f8 e2 4f 4f 4a 79 d1  |.....B.*...OOJy.|
+00000020  73 e6 4d 42 90 3c 06 f8  7b da 26 cc 58 be 97 f6  |s.MB.<..{.&.X...|
+00000030  41 32 fb 39 2f fa e1 bc  59 2b 45 17 03 01 00 20  |A2.9/...Y+E.... |
+00000040  93 6a a1 a6 a2 e6 be bb  be 2f 8f 0c 52 39 1c 6a  |.j......./..R9.j|
+00000050  6d 4c af 38 f7 60 8b ad  0e c7 62 0c 8b a4 42 14  |mL.8.`....b...B.|
+00000060  17 03 01 00 30 da b0 1b  ef cf 45 86 09 e9 be aa  |....0.....E.....|
+00000070  0f 71 af a3 86 d0 0f 2d  e8 76 39 9a c4 1f f5 c2  |.q.....-.v9.....|
+00000080  82 0a ee 34 0e a6 3b 19  b8 2c 10 ad fc 03 33 31  |...4..;..,....31|
+00000090  10 42 9b 6e 7b 15 03 01  00 20 ac 73 4d 4b 92 30  |.B.n{.... .sMK.0|
+000000a0  bf 4c bc 77 c1 87 d7 20  ad 82 bd 75 31 82 0d 34  |.L.w... ...u1..4|
+000000b0  cb b2 86 fd 4f 9c 84 a3  80 af                    |....O.....|
index 55cb487d12a9835b91c8b76eb9d05d2118b36847..33e8063ba60e5e89ba63ffb2516302276a5434ed 100644 (file)
@@ -1,8 +1,8 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 36 01 00 00  32 03 01 35 4a e8 32 84  |....6...2..5J.2.|
-00000010  51 68 04 7e d0 0f 43 94  c7 5d 44 d2 95 a3 12 63  |Qh.~..C..]D....c|
-00000020  77 c5 ce 78 5a 25 a3 81  df c4 6b 00 00 04 00 0a  |w..xZ%....k.....|
-00000030  00 ff 01 00 00 05 00 0f  00 01 01                 |...........|
+00000000  16 03 01 00 37 01 00 00  33 03 01 8d f4 8c 3d bd  |....7...3.....=.|
+00000010  d8 81 53 bb f5 bc 18 69  07 09 0d 05 93 4f 6f eb  |..S....i.....Oo.|
+00000020  fa fb 03 65 d4 49 a3 df  9f c3 a5 00 00 04 00 0a  |...e.I..........|
+00000030  00 ff 02 01 00 00 05 00  0f 00 01 01              |............|
 >>> Flow 2 (server to client)
 00000000  16 03 01 00 31 02 00 00  2d 03 01 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 01 00  |..A4......9.....|
 000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 01 00 86 10 00 00  82 00 80 1f 4d 12 64 f2  |............M.d.|
-00000010  72 22 86 4a 16 05 3f d2  1b e5 ed a7 f1 19 c4 6d  |r".J..?........m|
-00000020  1d 3a 5c f6 46 8f b9 4d  9e c4 d4 19 95 0a 63 9f  |.:\.F..M......c.|
-00000030  8a 41 1f fc d5 98 45 ca  69 33 37 64 d5 c8 0e 5a  |.A....E.i37d...Z|
-00000040  12 9f 06 54 8a 61 8b 13  f0 d8 fb b9 97 fb cd 1d  |...T.a..........|
-00000050  bd 6c 88 cc 98 57 c3 66  3a 86 04 c9 b9 21 c6 f2  |.l...W.f:....!..|
-00000060  f3 43 7d 4e bf 28 d5 a2  d7 39 e0 78 cb eb b4 af  |.C}N.(...9.x....|
-00000070  21 0e ae 4c 16 9b b3 49  5f 81 02 55 59 97 d9 d2  |!..L...I_..UY...|
-00000080  c4 e2 4c be 0a a6 41 62  48 1d 66 14 03 01 00 01  |..L...AbH.f.....|
-00000090  01 16 03 01 00 28 9d e0  c3 31 82 c2 48 5d fb 47  |.....(...1..H].G|
-000000a0  85 60 d4 17 d2 4f 4d 3c  64 db e4 49 1f a9 66 93  |.`...OM<d..I..f.|
-000000b0  72 6c 32 06 a5 0c 1f db  64 6d 54 71 fd 30        |rl2.....dmTq.0|
+00000000  16 03 01 00 86 10 00 00  82 00 80 6b 00 e3 47 e3  |...........k..G.|
+00000010  0d 22 44 53 7a b9 d1 14  4e e4 47 17 a1 e2 f5 d2  |."DSz...N.G.....|
+00000020  f7 82 2f 1b e2 3a 60 aa  79 36 fa 74 05 72 66 88  |../..:`.y6.t.rf.|
+00000030  3f 6a 57 8d 10 8a a1 80  3c 74 5b 29 c3 a1 b8 57  |?jW.....<t[)...W|
+00000040  20 cc 75 fc 0e 3c 09 06  46 52 b2 ca b2 cd bf 4c  | .u..<..FR.....L|
+00000050  b3 12 2b 59 f1 41 a2 c7  4c 62 c7 61 26 2b 89 fe  |..+Y.A..Lb.a&+..|
+00000060  01 9a b6 2b b4 15 75 05  4b f8 5b 04 9a 64 cc 06  |...+..u.K.[..d..|
+00000070  6b 8c 98 6d 51 37 50 b4  69 03 5c 9a ed e3 9a 23  |k..mQ7P.i.\....#|
+00000080  a9 68 e0 56 58 f7 f4 a0  d6 b4 55 14 03 01 00 01  |.h.VX.....U.....|
+00000090  01 16 03 01 00 28 9f ac  be d9 6f ab cb 0e 45 8a  |.....(....o...E.|
+000000a0  96 71 fd 23 39 b0 02 cc  a6 5a 7a 64 e2 29 9f 18  |.q.#9....Zzd.)..|
+000000b0  dc 25 84 ee 76 56 3c cc  d9 15 34 16 67 7e        |.%..vV<...4.g~|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 28 94 66 8f ad 8f  |..........(.f...|
-00000010  9f 00 72 f6 af 51 47 67  63 df 3f dd 17 09 0a c5  |..r..QGgc.?.....|
-00000020  bf f8 4d 66 39 f9 b5 47  01 f8 e8 6d ed b4 17 39  |..Mf9..G...m...9|
-00000030  ff 0a ca 17 03 01 00 18  68 93 94 51 12 b9 17 0b  |........h..Q....|
-00000040  d1 a0 22 fc cc c4 76 1a  1e 02 c6 20 5e 74 83 4c  |.."...v.... ^t.L|
-00000050  17 03 01 00 28 08 bd 86  07 84 90 78 bd 1d 90 ce  |....(......x....|
-00000060  09 80 bb d8 de fd 39 82  4b c4 0d 06 f3 65 f5 5b  |......9.K....e.[|
-00000070  3d c3 fd 69 80 1f 51 ce  1d 98 f1 05 fa 15 03 01  |=..i..Q.........|
-00000080  00 18 ed 48 04 21 85 77  d7 b6 29 e3 25 af ea ec  |...H.!.w..).%...|
-00000090  3e 41 82 a0 ca 7d 44 79  8a 0b                    |>A...}Dy..|
+00000000  14 03 01 00 01 01 16 03  01 00 28 f4 cf 23 f8 86  |..........(..#..|
+00000010  83 df 44 af 1c 25 b1 51  84 5b 6a f3 0e 6b 47 5c  |..D..%.Q.[j..kG\|
+00000020  2a 59 67 db 42 11 f9 53  58 4e db 6f 00 b2 20 5b  |*Yg.B..SXN.o.. [|
+00000030  ae a3 43 17 03 01 00 18  df e0 22 d6 05 ab 79 c7  |..C......."...y.|
+00000040  87 8a 82 83 01 bc 06 45  36 74 4d 1c 40 96 97 5f  |.......E6tM.@.._|
+00000050  17 03 01 00 28 49 bd b7  e9 41 6b eb b1 aa 89 60  |....(I...Ak....`|
+00000060  21 91 df bf f4 7a 49 9d  54 04 4a 16 1a d1 44 9a  |!....zI.T.J...D.|
+00000070  09 6c 4f 01 3d c0 2f d5  a3 72 a3 b2 fe 15 03 01  |.lO.=./..r......|
+00000080  00 18 5c 7a de a0 ef ed  56 99 99 01 5f b4 32 b3  |..\z....V..._.2.|
+00000090  00 be c6 cc 7e bb 6f 82  7d f7                    |....~.o.}.|
index 46713022890f527cb1031bddcc51d97376a6d7c4..e51bc17ee75a62bbadc11a7afa54410e0fdb4aea 100644 (file)
@@ -1,8 +1,8 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 36 01 00 00  32 03 01 8c 5a 87 31 6a  |....6...2...Z.1j|
-00000010  8c 7a d5 26 4b 94 17 27  fc a2 c0 5f b5 bc 3f 10  |.z.&K..'..._..?.|
-00000020  80 0e e0 1e 36 80 4b 91  61 77 d4 00 00 04 00 2f  |....6.K.aw...../|
-00000030  00 ff 01 00 00 05 00 0f  00 01 01                 |...........|
+00000000  16 03 01 00 37 01 00 00  33 03 01 39 72 8e 06 ed  |....7...3..9r...|
+00000010  d2 74 5c 02 74 0e 2b 7a  bd 54 ce be 17 a0 4f 1a  |.t\.t.+z.T....O.|
+00000020  c5 72 b1 e8 3e 2e 90 68  ff fc 6e 00 00 04 00 2f  |.r..>..h..n..../|
+00000030  00 ff 02 01 00 00 05 00  0f 00 01 01              |............|
 >>> Flow 2 (server to client)
 00000000  16 03 01 00 31 02 00 00  2d 03 01 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 01 00  |..A4......9.....|
 000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 01 00 86 10 00 00  82 00 80 31 f5 2e e4 c7  |...........1....|
-00000010  f5 76 d6 f7 2d 1b 8d 4d  a9 2a 43 84 b2 0b 08 d6  |.v..-..M.*C.....|
-00000020  4d d9 9a eb 4b 01 49 6e  11 45 43 0d 31 a7 c3 66  |M...K.In.EC.1..f|
-00000030  da 1c 92 68 fb 3d 36 27  94 2f 67 ae 3d 31 a3 8f  |...h.=6'./g.=1..|
-00000040  01 5a d9 17 92 bc 20 7c  cb ae b4 ca 4c ce d4 a9  |.Z.... |....L...|
-00000050  2c 1d fe fc 3c a9 14 31  1d 65 08 d8 6e 8d ac 9d  |,...<..1.e..n...|
-00000060  21 ee 63 4a e2 da 3c 0e  b1 34 8f 6e 20 dd d4 d4  |!.cJ..<..4.n ...|
-00000070  d8 16 27 5d 02 54 e6 ec  5f 43 84 5b 21 24 ef 5d  |..'].T.._C.[!$.]|
-00000080  45 c4 2b 2c 98 7d 50 dc  0b fc 76 14 03 01 00 01  |E.+,.}P...v.....|
-00000090  01 16 03 01 00 30 ef 50  ea 3c e3 b7 a8 5b 9a d2  |.....0.P.<...[..|
-000000a0  11 69 0f d0 5e 79 c8 cb  68 4a ac 16 ef b4 de 1f  |.i..^y..hJ......|
-000000b0  21 0b 8e 91 cb 70 3f 02  bd 45 c1 34 02 e0 66 8a  |!....p?..E.4..f.|
-000000c0  00 ea 6c 5a 96 41                                 |..lZ.A|
+00000000  16 03 01 00 86 10 00 00  82 00 80 0e a2 23 fe 89  |.............#..|
+00000010  46 08 20 98 da 4d 91 a4  48 40 ab 03 df 1f 00 67  |F. ..M..H@.....g|
+00000020  f3 fb fb 22 f7 8e d6 65  2c 43 a7 f4 9c 0e 25 cc  |..."...e,C....%.|
+00000030  d9 3b b5 58 df bd 93 27  1c df 69 37 27 01 cb 0d  |.;.X...'..i7'...|
+00000040  b4 f4 a6 8d 91 fe ef dc  9a e2 09 7c 53 1a 73 6d  |...........|S.sm|
+00000050  b9 f6 89 0a 1f 94 f0 26  25 ef 73 54 20 d5 8d 77  |.......&%.sT ..w|
+00000060  36 2e e7 4c 9a f1 4a be  ae 6e b6 be 16 10 31 42  |6..L..J..n....1B|
+00000070  9e d2 49 41 2c 32 52 11  bc 85 2d fa 39 80 9b f9  |..IA,2R...-.9...|
+00000080  95 fe e8 88 2a a2 57 65  7e 38 b2 14 03 01 00 01  |....*.We~8......|
+00000090  01 16 03 01 00 30 1c 6f  91 45 16 ed 25 82 ee 5f  |.....0.o.E..%.._|
+000000a0  f9 f0 09 0c a4 ad 56 61  e5 b7 a2 05 50 02 b8 80  |......Va....P...|
+000000b0  ef 73 d1 11 3c 25 50 44  0d ba b5 7c fd 5d 7a df  |.s..<%PD...|.]z.|
+000000c0  14 62 1b 29 be 29                                 |.b.).)|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 99 2c 65 32 5f  |..........0.,e2_|
-00000010  53 37 d8 c2 98 87 f4 68  b6 d7 52 6a 14 c7 df 6e  |S7.....h..Rj...n|
-00000020  bb ce ae 31 d4 04 24 4d  e9 c2 39 7b 68 a7 fa 90  |...1..$M..9{h...|
-00000030  c1 30 14 a2 20 c0 8d e1  2a dc 22 17 03 01 00 20  |.0.. ...*.".... |
-00000040  41 c5 03 05 20 53 e9 fa  0a 26 38 ab 84 6a 5e 36  |A... S...&8..j^6|
-00000050  1b 03 80 2f c3 5c 0b 2c  bd 7f 79 68 bb ab 4d 70  |.../.\.,..yh..Mp|
-00000060  17 03 01 00 30 a1 04 3e  f4 a2 54 7a e7 09 0f 20  |....0..>..Tz... |
-00000070  38 f8 9e bb 1b 61 28 bf  46 e8 75 56 b4 c3 93 b9  |8....a(.F.uV....|
-00000080  8c 18 3e 8e af 9f 59 1a  96 be db 61 80 56 c6 09  |..>...Y....a.V..|
-00000090  3c 21 02 37 d2 15 03 01  00 20 13 d1 81 7d ca 04  |<!.7..... ...}..|
-000000a0  2b c3 fc fa 06 5b b4 98  59 27 0d 07 2a 39 3c 6f  |+....[..Y'..*9<o|
-000000b0  8d 64 83 17 0f ba ec 22  21 36                    |.d....."!6|
+00000000  14 03 01 00 01 01 16 03  01 00 30 5e 8c b1 dc 1f  |..........0^....|
+00000010  b3 18 85 4a 46 02 fb 34  e4 05 56 78 4c e3 34 63  |...JF..4..VxL.4c|
+00000020  06 08 b4 ee 36 e2 28 ab  c9 98 ee 26 4e 5b 5d 42  |....6.(....&N[]B|
+00000030  5f f8 e1 d1 2f 8b c8 ef  5a 65 40 17 03 01 00 20  |_.../...Ze@.... |
+00000040  e7 92 6e b1 60 b9 f8 cd  53 d3 37 5b 44 74 1c af  |..n.`...S.7[Dt..|
+00000050  90 93 13 8e 55 25 cc 9f  57 8c f3 06 f7 ba e0 f9  |....U%..W.......|
+00000060  17 03 01 00 30 fc 83 e6  4e 8c 65 8f d1 7c c7 f4  |....0...N.e..|..|
+00000070  8b 68 0d 5d da 8e 49 45  68 ea 4c e3 7f 7d 84 87  |.h.]..IEh.L..}..|
+00000080  2f 63 e0 fb 43 24 04 cd  e2 38 32 50 0a 4c 43 ce  |/c..C$...82P.LC.|
+00000090  3b 12 a5 6b 99 15 03 01  00 20 2a 42 d8 57 26 79  |;..k..... *B.W&y|
+000000a0  51 ee 79 9d b2 83 b8 49  a4 e9 a2 08 34 73 c4 f5  |Q.y....I....4s..|
+000000b0  53 21 4b 78 ec 5b ce b4  4e a0                    |S!Kx.[..N.|
index b5cb479c283eda63b40908fdf900990452c9fd71..8d5446341bab8646d3a2142a85b70a6cdd7c0382 100644 (file)
@@ -1,8 +1,8 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 36 01 00 00  32 03 01 c5 fc 32 c0 09  |....6...2....2..|
-00000010  47 0b a9 f3 72 c9 6c 3a  e0 94 33 48 35 ac b9 3b  |G...r.l:..3H5..;|
-00000020  da 5f 8b 6e 0c 54 c3 16  f0 39 bd 00 00 04 00 05  |._.n.T...9......|
-00000030  00 ff 01 00 00 05 00 0f  00 01 01                 |...........|
+00000000  16 03 01 00 37 01 00 00  33 03 01 b3 82 99 50 b0  |....7...3.....P.|
+00000010  1e 7a 46 48 9d 8e 93 32  3b 01 bc 50 e9 5c eb 91  |.zFH...2;..P.\..|
+00000020  25 4b c1 ea 0a 91 c9 b3  2b 54 90 00 00 04 00 05  |%K......+T......|
+00000030  00 ff 02 01 00 00 05 00  0f 00 01 01              |............|
 >>> Flow 2 (server to client)
 00000000  16 03 01 00 31 02 00 00  2d 03 01 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 01 00  |..A4......9.....|
 000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 01 00 86 10 00 00  82 00 80 6a ad 7f e3 26  |...........j...&|
-00000010  71 da 48 af 11 63 de 2e  e8 50 f9 6a be 04 3d 17  |q.H..c...P.j..=.|
-00000020  d1 29 fe 2c 7f b6 26 c1  7e 0b 18 1c 41 62 5c 91  |.).,..&.~...Ab\.|
-00000030  ee 26 9c 92 f5 d1 e9 29  e1 ca a7 01 6a 41 b9 00  |.&.....)....jA..|
-00000040  34 1d 5b c6 28 0e 1a 8f  32 c5 03 e7 a1 8f 89 1b  |4.[.(...2.......|
-00000050  af 13 22 2b 5b e8 76 2d  00 ac da 27 75 95 75 e7  |.."+[.v-...'u.u.|
-00000060  00 00 39 2c bf f2 01 57  e6 29 e3 26 b1 6b ae c5  |..9,...W.).&.k..|
-00000070  8d ce d2 36 b2 94 1f 9c  30 5e b2 16 3d 20 cf 4d  |...6....0^..= .M|
-00000080  88 f5 ac 4c 27 e3 f5 86  ef 9e dc 14 03 01 00 01  |...L'...........|
-00000090  01 16 03 01 00 24 48 d8  80 c4 37 22 31 99 53 30  |.....$H...7"1.S0|
-000000a0  5b 00 07 7e 87 2e 59 9a  d9 0c 42 9e dd ed da 89  |[..~..Y...B.....|
-000000b0  1a 1f cb ab 55 0c ba d9  a9 c0                    |....U.....|
+00000000  16 03 01 00 86 10 00 00  82 00 80 05 1c 93 2a 69  |..............*i|
+00000010  f7 0b 1d 59 ea ca c2 4a  b1 7c ef 22 4c 7b 31 5f  |...Y...J.|."L{1_|
+00000020  18 8d 32 b6 db 75 8c f8  45 07 27 e1 9f 3f 9d 0b  |..2..u..E.'..?..|
+00000030  02 ac 2c 3f aa bf 79 fb  d4 af 98 0c b2 c0 03 4b  |..,?..y........K|
+00000040  86 26 c3 30 f3 ea 2b 1a  ab 70 90 8d 01 2b 0e ff  |.&.0..+..p...+..|
+00000050  4c 10 9a 29 75 cb 14 bb  85 80 98 35 fb 82 e8 b5  |L..)u......5....|
+00000060  80 6f 9d e6 3b b6 14 36  bb 61 8e 18 f2 6b da 09  |.o..;..6.a...k..|
+00000070  71 9c 6d 1e c3 60 a9 c5  8b 4e 77 41 db ec 12 49  |q.m..`...NwA...I|
+00000080  a4 c2 e2 10 ce 7f 18 05  b9 74 aa 14 03 01 00 01  |.........t......|
+00000090  01 16 03 01 00 24 3d 90  d0 f6 6f 15 94 05 a0 fb  |.....$=...o.....|
+000000a0  43 83 55 b5 b1 ef e5 fd  fc 00 d3 d5 25 b4 7c 9f  |C.U.........%.|.|
+000000b0  e0 82 99 2a 6d 5a 26 7c  05 21                    |...*mZ&|.!|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 24 ae 00 c8 14 67  |..........$....g|
-00000010  4b b5 21 96 98 91 d6 27  40 9b 5e a5 86 53 56 f3  |K.!....'@.^..SV.|
-00000020  f6 dc 7e b2 49 78 4b 4d  57 7c 62 a5 f2 16 8f 17  |..~.IxKMW|b.....|
-00000030  03 01 00 21 34 e3 48 58  1c 67 fb 3a 46 28 5d a1  |...!4.HX.g.:F(].|
-00000040  19 66 58 b1 bb fb e7 17  71 07 3f 0a d0 7c c9 24  |.fX.....q.?..|.$|
-00000050  c7 ef 41 af 62 15 03 01  00 16 dd dc 16 dc 16 cc  |..A.b...........|
-00000060  0d f3 2c 29 00 c0 4f 01  68 05 92 a0 f7 ad e2 63  |..,)..O.h......c|
+00000000  14 03 01 00 01 01 16 03  01 00 24 28 d0 1f ec 1d  |..........$(....|
+00000010  9e 1d e3 80 6b 6d 3e 8b  c5 f7 9c 14 a9 0b c3 53  |....km>........S|
+00000020  fd 48 d0 b3 eb d1 49 97  97 71 e9 36 b9 e6 3a 17  |.H....I..q.6..:.|
+00000030  03 01 00 21 c3 b6 2e 02  05 86 0f 57 04 dd 88 33  |...!.......W...3|
+00000040  0a ed 1d d5 a8 0f 55 54  c5 8c 87 5b 11 b7 80 7f  |......UT...[....|
+00000050  30 79 e0 64 ee 15 03 01  00 16 b1 50 de 3d 18 05  |0y.d.......P.=..|
+00000060  2f db 37 4c db 62 f1 c8  d5 19 ca c2 fb a5 8a 37  |/.7L.b.........7|
index 2d8dfbc3b491e1bdbfd4f1c5ec332679dfa7a010..a6e2137e50491a28674f9bab413899324164663d 100644 (file)
@@ -1,17 +1,17 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 d4 01 00 00  d0 03 02 74 2d da 6d 98  |...........t-.m.|
-00000010  ad 3e a5 ec 90 ea d1 5b  f0 e0 a7 45 33 d9 5e 8d  |.>.....[...E3.^.|
-00000020  0f 1d 01 16 6d 00 31 65  ed 50 88 00 00 5e c0 14  |....m.1e.P...^..|
-00000030  c0 0a 00 39 00 38 00 88  00 87 c0 0f c0 05 00 35  |...9.8.........5|
-00000040  00 84 c0 13 c0 09 00 33  00 32 00 9a 00 99 00 45  |.......3.2.....E|
-00000050  00 44 c0 0e c0 04 00 2f  00 96 00 41 00 07 c0 11  |.D...../...A....|
-00000060  c0 07 c0 0c c0 02 00 05  00 04 c0 12 c0 08 00 16  |................|
-00000070  00 13 c0 0d c0 03 00 0a  00 15 00 12 00 09 00 14  |................|
-00000080  00 11 00 08 00 06 00 03  00 ff 56 00 01 00 00 49  |..........V....I|
-00000090  00 0b 00 04 03 00 01 02  00 0a 00 34 00 32 00 0e  |...........4.2..|
-000000a0  00 0d 00 19 00 0b 00 0c  00 18 00 09 00 0a 00 16  |................|
-000000b0  00 17 00 08 00 06 00 07  00 14 00 15 00 04 00 05  |................|
-000000c0  00 12 00 13 00 01 00 02  00 03 00 0f 00 10 00 11  |................|
-000000d0  00 23 00 00 00 0f 00 01  01                       |.#.......|
+00000000  16 03 01 00 cf 01 00 00  cb 03 02 ee 33 c1 3f a6  |............3.?.|
+00000010  62 ba a6 4f c7 32 25 0f  15 66 f7 35 a2 cf c0 cd  |b..O.2%..f.5....|
+00000020  48 93 77 1c 04 1f fb 65  41 37 ca 00 00 70 c0 14  |H.w....eA7...p..|
+00000030  c0 0a 00 39 00 38 00 37  00 36 00 88 00 87 00 86  |...9.8.7.6......|
+00000040  00 85 c0 0f c0 05 00 35  00 84 c0 13 c0 09 00 33  |.......5.......3|
+00000050  00 32 00 31 00 30 00 9a  00 99 00 98 00 97 00 45  |.2.1.0.........E|
+00000060  00 44 00 43 00 42 c0 0e  c0 04 00 2f 00 96 00 41  |.D.C.B...../...A|
+00000070  00 07 c0 11 c0 07 c0 0c  c0 02 00 05 00 04 c0 12  |................|
+00000080  c0 08 00 16 00 13 00 10  00 0d c0 0d c0 03 00 0a  |................|
+00000090  00 15 00 12 00 0f 00 0c  00 09 00 ff 56 00 02 01  |............V...|
+000000a0  00 00 31 00 0b 00 04 03  00 01 02 00 0a 00 1c 00  |..1.............|
+000000b0  1a 00 17 00 19 00 1c 00  1b 00 18 00 1a 00 16 00  |................|
+000000c0  0e 00 0d 00 0b 00 0c 00  09 00 0a 00 23 00 00 00  |............#...|
+000000d0  0f 00 01 01                                       |....|
 >>> Flow 2 (server to client)
 00000000  15 03 02 00 02 02 56                              |......V|
index dc5e765e5438ae0f1823d8098811be05f93c9eaa..b3916f9fd1c6210bff9dd20b892337fe373fdb25 100644 (file)
@@ -1,8 +1,8 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 36 01 00 00  32 03 02 ff e1 a1 04 0b  |....6...2.......|
-00000010  c2 dc fb 7d 07 61 44 9b  00 67 fe 38 73 f5 fc 4e  |...}.aD..g.8s..N|
-00000020  35 94 0a d5 c1 d0 e7 54  dc 44 1f 00 00 04 00 05  |5......T.D......|
-00000030  00 ff 01 00 00 05 00 0f  00 01 01                 |...........|
+00000000  16 03 01 00 37 01 00 00  33 03 02 95 4a cf f5 14  |....7...3...J...|
+00000010  56 9b d6 be 0c ba 0d b2  ad 65 47 d2 c6 ce 84 c9  |V........eG.....|
+00000020  f4 80 2a 4e 75 df ff 48  cf 48 9b 00 00 04 00 05  |..*Nu..H.H......|
+00000030  00 ff 02 01 00 00 05 00  0f 00 01 01              |............|
 >>> Flow 2 (server to client)
 00000000  16 03 02 00 31 02 00 00  2d 03 02 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 02 00  |..A4......9.....|
 000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 02 00 86 10 00 00  82 00 80 4c e0 4d 6a 19  |...........L.Mj.|
-00000010  a2 72 2a 3d 41 14 a7 b3  0a 25 11 bf c9 9f cf 8c  |.r*=A....%......|
-00000020  3c 0b 01 49 aa f1 59 4b  60 ac e5 72 9b ec 20 41  |<..I..YK`..r.. A|
-00000030  2f 7e ef bf e0 fe 13 c0  1d fd 51 c5 08 c6 9a 9e  |/~........Q.....|
-00000040  74 88 c7 e3 36 99 73 fd  00 2d a2 6a bd 25 f2 d7  |t...6.s..-.j.%..|
-00000050  24 fd fd ab 0c e0 18 38  ba 7b f0 c9 c0 58 a6 d0  |$......8.{...X..|
-00000060  4e e2 59 70 aa f4 52 34  12 a0 ec a4 53 1e 8b ee  |N.Yp..R4....S...|
-00000070  3e bf a4 87 da 02 4c 95  bd 10 af e8 88 c9 ce 87  |>.....L.........|
-00000080  3c 9e 91 70 91 a0 85 18  84 e4 e0 14 03 02 00 01  |<..p............|
-00000090  01 16 03 02 00 24 c5 c0  27 71 49 ad ed 37 e6 5d  |.....$..'qI..7.]|
-000000a0  1b 78 3e 74 15 b7 61 e5  f3 af 1e d0 a2 85 b3 13  |.x>t..a.........|
-000000b0  6e 5e 9a c7 3d 47 32 4d  1b 8d                    |n^..=G2M..|
+00000000  16 03 02 00 86 10 00 00  82 00 80 19 c3 d4 f2 e4  |................|
+00000010  bf 4a 52 90 a4 65 f6 e7  29 1a 7f ef 0e a4 1e b4  |.JR..e..).......|
+00000020  c2 df b2 83 43 4a 1a f4  b6 cd 51 a5 24 62 3f e1  |....CJ....Q.$b?.|
+00000030  fb 5f 7e b1 10 08 3b 8a  ab eb 3a a3 72 ba 31 1c  |._~...;...:.r.1.|
+00000040  23 bd ef 2e 3d 13 dc 61  88 a6 af ca 80 82 5d e4  |#...=..a......].|
+00000050  d6 a2 d3 13 80 87 c6 ad  a5 13 4e f1 b6 a0 5d fa  |..........N...].|
+00000060  ed a7 0d 37 58 f1 54 38  18 f5 be db 90 9f 07 4a  |...7X.T8.......J|
+00000070  67 25 c9 8d 9d 5e 07 62  ca db 72 74 b5 bd a0 ed  |g%...^.b..rt....|
+00000080  d0 95 9f 3e cd 37 b8 96  df df 3b 14 03 02 00 01  |...>.7....;.....|
+00000090  01 16 03 02 00 24 80 53  7a 8f 23 06 a7 6b e6 be  |.....$.Sz.#..k..|
+000000a0  61 c2 1a c8 35 30 6b e2  2f 82 f3 46 ff e3 1d bd  |a...50k./..F....|
+000000b0  68 e9 a2 78 49 33 05 ca  d9 41                    |h..xI3...A|
 >>> Flow 4 (server to client)
-00000000  14 03 02 00 01 01 16 03  02 00 24 31 22 76 4d 43  |..........$1"vMC|
-00000010  7a 8a 58 2c 7d 1c 41 39  bf 08 7e 82 17 55 52 b3  |z.X,}.A9..~..UR.|
-00000020  81 bd 7a f8 3c bf 9c 2b  f0 9b 3f 65 f5 42 15 17  |..z.<..+..?e.B..|
-00000030  03 02 00 21 b1 cc e5 56  16 70 58 0b 91 3c 8c 46  |...!...V.pX..<.F|
-00000040  0e 3b b6 fe 32 5d 2e b0  8c 6a 1c a0 82 c9 43 81  |.;..2]...j....C.|
-00000050  cf 07 25 47 c9 15 03 02  00 16 53 91 04 70 ba 03  |..%G......S..p..|
-00000060  53 69 57 86 3b 2f 8b 97  37 7c b8 85 46 b6 72 42  |SiW.;/..7|..F.rB|
+00000000  14 03 02 00 01 01 16 03  02 00 24 8f 06 3e 7b 8c  |..........$..>{.|
+00000010  fb f2 3d 9e 5c a9 46 56  79 2a 3a ba ad 25 30 57  |..=.\.FVy*:..%0W|
+00000020  f9 f1 16 70 51 5d 73 7e  47 74 8d c0 84 b0 31 17  |...pQ]s~Gt....1.|
+00000030  03 02 00 21 76 09 88 df  7e f7 2f c9 3d 86 b9 30  |...!v...~./.=..0|
+00000040  b0 5c ac ea db c6 d0 d5  69 55 91 7b a1 72 0b 4d  |.\......iU.{.r.M|
+00000050  7d ae 6f aa 50 15 03 02  00 16 8c 31 73 86 1a c7  |}.o.P......1s...|
+00000060  ef 08 52 8a 7d 30 b8 00  3b 62 4d 21 7b 81 2c 76  |..R.}0..;bM!{.,v|
index cbfeb42eb06deaf96867e6c378fa4be379e267f8..df832d7dea769ed30628a14ec9223bdfafadcc50 100644 (file)
@@ -1,7 +1,7 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 01 4c 01 00 01  48 03 03 44 3b 24 ee 2f  |....L...H..D;$./|
-00000010  63 3d ca bd 3e c5 bf a2  24 f1 59 c3 54 dc f0 43  |c=..>...$.Y.T..C|
-00000020  15 c4 51 f2 29 ea 1b ce  2c fe af 00 00 b6 c0 30  |..Q.)...,......0|
+00000000  16 03 01 01 4d 01 00 01  49 03 03 ac 76 61 d8 20  |....M...I...va. |
+00000010  b3 c3 1d c2 3d c2 a4 b9  e2 46 a2 a1 0a 5e 08 56  |....=....F...^.V|
+00000020  4a aa 59 43 42 d6 21 9c  46 0c 21 00 00 b6 c0 30  |J.YCB.!.F.!....0|
 00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
 00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
 00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
 000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
 000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
 000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
-000000e0  00 09 00 ff 01 00 00 69  00 0b 00 04 03 00 01 02  |.......i........|
-000000f0  00 0a 00 1c 00 1a 00 17  00 19 00 1c 00 1b 00 18  |................|
-00000100  00 1a 00 16 00 0e 00 0d  00 0b 00 0c 00 09 00 0a  |................|
-00000110  00 23 00 00 00 0d 00 20  00 1e 06 01 06 02 06 03  |.#..... ........|
-00000120  05 01 05 02 05 03 04 01  04 02 04 03 03 01 03 02  |................|
-00000130  03 03 02 01 02 02 02 03  00 0f 00 01 01 00 10 00  |................|
-00000140  10 00 0e 06 70 72 6f 74  6f 32 06 70 72 6f 74 6f  |....proto2.proto|
-00000150  31                                                |1|
+000000e0  00 09 00 ff 02 01 00 00  69 00 0b 00 04 03 00 01  |........i.......|
+000000f0  02 00 0a 00 1c 00 1a 00  17 00 19 00 1c 00 1b 00  |................|
+00000100  18 00 1a 00 16 00 0e 00  0d 00 0b 00 0c 00 09 00  |................|
+00000110  0a 00 23 00 00 00 0d 00  20 00 1e 06 01 06 02 06  |..#..... .......|
+00000120  03 05 01 05 02 05 03 04  01 04 02 04 03 03 01 03  |................|
+00000130  02 03 03 02 01 02 02 02  03 00 0f 00 01 01 00 10  |................|
+00000140  00 10 00 0e 06 70 72 6f  74 6f 32 06 70 72 6f 74  |.....proto2.prot|
+00000150  6f 31                                             |o1|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 42 02 00 00  3e 03 03 00 00 00 00 00  |....B...>.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002d0  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
 000002e0  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 000002f0  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
-00000300  a6 b5 68 1a 41 03 56 6b  dc 5a 89 05 01 00 80 40  |..h.A.Vk.Z.....@|
-00000310  93 b2 1f 79 3d 56 c0 ae  94 87 c0 a7 28 ef 1d 15  |...y=V......(...|
-00000320  be 4b fb 66 e0 60 2c a3  57 ee 56 7d d6 89 b8 8e  |.K.f.`,.W.V}....|
-00000330  8f 0f 3f 1b c6 9f a4 1d  34 60 b6 9c e9 9b a9 27  |..?.....4`.....'|
-00000340  d0 45 7b 04 71 2d db 9c  67 1b d5 d4 fe 19 69 59  |.E{.q-..g.....iY|
-00000350  71 8a 35 75 33 a8 c9 f2  4d c4 8f 40 17 a7 25 53  |q.5u3...M..@..%S|
-00000360  57 c5 cd ee df a9 3b a3  61 ab e2 a2 ca de 5c 08  |W.....;.a.....\.|
-00000370  3d 5b a2 ef cd c8 bc 16  1f 1d 0f 83 9e b7 20 f5  |=[............ .|
-00000380  89 3f 09 ba 2e da 12 34  81 e5 2f 8d 3c 90 89 16  |.?.....4../.<...|
+00000300  a6 b5 68 1a 41 03 56 6b  dc 5a 89 05 01 00 80 aa  |..h.A.Vk.Z......|
+00000310  8c a6 e1 51 65 fc 99 37  cf 63 d8 fd 04 52 d5 50  |...Qe..7.c...R.P|
+00000320  1f 0a f5 90 58 48 19 8d  d8 0b 64 23 e4 24 56 b4  |....XH....d#.$V.|
+00000330  e5 87 0f 88 a1 7a 29 fa  88 79 99 75 6d 53 a9 50  |.....z)..y.umS.P|
+00000340  a4 9c b9 47 c2 51 87 10  b9 a5 e3 6f a9 38 b8 83  |...G.Q.....o.8..|
+00000350  0d 39 b5 28 27 5f ec 9d  a3 2d 1c 53 6b da 93 0d  |.9.('_...-.Sk...|
+00000360  cc cf 0c 27 7e d2 f0 05  d5 c0 04 dc 6d d4 2e 03  |...'~.......m...|
+00000370  a7 16 98 58 e4 8d fd 14  6b bb 0c 09 b0 16 35 9e  |...X....k.....5.|
+00000380  78 3a 29 21 b5 2f 13 37  94 ae f7 fe 54 89 c0 16  |x:)!./.7....T...|
 00000390  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 8b a2 de a6 1e  |....F...BA......|
-00000010  d9 22 3c 03 4a be 49 2f  40 e3 1e e0 b4 76 7f 78  |."<.J.I/@....v.x|
-00000020  96 22 8d 8d c9 45 3b d8  7a ce e3 16 3d 37 ec 80  |."...E;.z...=7..|
-00000030  aa 3f d5 19 de c1 2c 7b  7f eb 3c fc 5d c3 52 3b  |.?....,{..<.].R;|
-00000040  d4 22 25 1c c7 1f 39 c5  23 bd 73 14 03 03 00 01  |."%...9.#.s.....|
-00000050  01 16 03 03 00 28 c8 53  0a ad c2 f6 7e 18 08 a3  |.....(.S....~...|
-00000060  29 27 20 1c 6c 1d 6c d8  8f 05 31 de e6 ab 7f 22  |)' .l.l...1...."|
-00000070  93 6a fb ef b0 f8 43 a9  d3 4f 9d 04 b5 9a        |.j....C..O....|
+00000000  16 03 03 00 46 10 00 00  42 41 04 35 ca 56 91 15  |....F...BA.5.V..|
+00000010  4f dd af 97 f2 2d fb df  54 2b 80 98 18 bb 33 54  |O....-..T+....3T|
+00000020  3f 7e 66 21 d3 81 38 f9  a4 b5 b9 a6 46 9a 52 8b  |?~f!..8.....F.R.|
+00000030  98 f7 81 1f 77 81 78 38  01 c5 3b fb 7a b7 53 e7  |....w.x8..;.z.S.|
+00000040  ae c3 4c 2e 73 f4 8e 3a  36 0d 43 14 03 03 00 01  |..L.s..:6.C.....|
+00000050  01 16 03 03 00 28 38 26  8e 03 ad 81 9b a0 41 d9  |.....(8&......A.|
+00000060  c0 11 3f 36 dc 6b ab 6c  29 dc df 02 a3 fe b0 0f  |..?6.k.l).......|
+00000070  2e b1 c6 44 39 42 d5 ef  29 30 d8 e0 f1 f9        |...D9B..)0....|
 >>> Flow 4 (server to client)
 00000000  16 03 03 00 82 04 00 00  7e 00 00 00 00 00 78 50  |........~.....xP|
 00000010  46 ad c1 db a8 38 86 7b  2b bb fd d0 c3 42 3e 00  |F....8.{+....B>.|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 94  |................|
-00000030  6f ec 80 83 61 8e d9 64  ac a2 ee 3b 69 31 79 e1  |o...a..d...;i1y.|
-00000040  53 0a 92 1d aa 23 09 c2  49 02 2d 0d 1d c1 63 d6  |S....#..I.-...c.|
-00000050  21 56 c7 24 02 28 d5 f1  11 b0 e7 1b 4a 7c 55 af  |!V.$.(......J|U.|
-00000060  1b c8 32 4c 5b 33 94 b0  ed b0 2f 52 c4 52 81 ee  |..2L[3..../R.R..|
-00000070  60 6f 66 fb f5 db dd f9  1e 30 11 d4 ca 75 0e 2b  |`of......0...u.+|
-00000080  ff d0 e5 f2 68 a4 e7 14  03 03 00 01 01 16 03 03  |....h...........|
-00000090  00 28 00 00 00 00 00 00  00 00 67 3b 4a ba f3 27  |.(........g;J..'|
-000000a0  c8 45 94 68 36 5a 40 e1  dc 67 9b d4 45 58 e9 24  |.E.h6Z@..g..EX.$|
-000000b0  31 85 3a f8 5d cb 84 8e  64 05 17 03 03 00 25 00  |1.:.]...d.....%.|
-000000c0  00 00 00 00 00 00 01 35  d9 ba 0a e2 3e fd a2 80  |.......5....>...|
-000000d0  10 0e 38 7b ad 85 85 48  6a 2a ab 2a 46 c3 59 96  |..8{...Hj*.*F.Y.|
-000000e0  fd 75 11 5d 15 03 03 00  1a 00 00 00 00 00 00 00  |.u.]............|
-000000f0  02 0b 4d a5 89 4d 86 47  14 60 27 f8 09 bc c9 4d  |..M..M.G.`'....M|
-00000100  00 31 cb                                          |.1.|
+00000030  6f ec 80 83 61 fb fb 41  b1 31 e9 71 75 43 c3 74  |o...a..A.1.quC.t|
+00000040  a1 a0 ac fb 97 b7 69 ee  a6 2f e3 a3 dd 9f de e4  |......i../......|
+00000050  80 9d d7 69 1a 2c 0b b4  02 bd ef e2 6a c1 ca 30  |...i.,......j..0|
+00000060  8b 9d 60 f9 fe 33 94 53  3a 14 a3 1a aa 5a ba ff  |..`..3.S:....Z..|
+00000070  1e 94 fd 4f e7 90 0b 09  ee 80 f3 d6 d5 c0 48 83  |...O..........H.|
+00000080  98 20 d7 a4 07 99 e0 14  03 03 00 01 01 16 03 03  |. ..............|
+00000090  00 28 00 00 00 00 00 00  00 00 0d 66 de 91 4a 97  |.(.........f..J.|
+000000a0  21 c6 d2 d7 df 68 9b 7e  f6 43 73 02 66 b3 5a d6  |!....h.~.Cs.f.Z.|
+000000b0  92 48 c2 c1 11 fc cd 1e  2e 4b 17 03 03 00 25 00  |.H.......K....%.|
+000000c0  00 00 00 00 00 00 01 72  0c 48 75 fa b2 8b 23 09  |.......r.Hu...#.|
+000000d0  be 76 36 a4 bc e0 62 ef  bd 79 8e de 6b 39 4b 55  |.v6...b..y..k9KU|
+000000e0  8d 3c ca 14 15 03 03 00  1a 00 00 00 00 00 00 00  |.<..............|
+000000f0  02 74 5f 79 31 41 4f f5  4d 02 96 bc c3 9a 85 92  |.t_y1AO.M.......|
+00000100  44 e1 76                                          |D.v|
index af75445dc5559e9d32b5dc74acb9b5c2583a55be..35bfdc1062096e74992dafdedfcc23781258a618 100644 (file)
@@ -1,7 +1,7 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 01 4c 01 00 01  48 03 03 1d 1a f7 e5 ad  |....L...H.......|
-00000010  a4 5c fd 61 b4 c2 25 33  c7 b9 fc fb 2b a5 4b fe  |.\.a..%3....+.K.|
-00000020  16 84 55 4b 9f 68 73 61  b8 92 4d 00 00 b6 c0 30  |..UK.hsa..M....0|
+00000000  16 03 01 01 4d 01 00 01  49 03 03 73 f2 f2 44 4f  |....M...I..s..DO|
+00000010  87 05 77 e2 e7 07 ca c7  d4 36 37 4e d9 17 ba ff  |..w......67N....|
+00000020  b0 e1 47 65 f8 7f fd 7a  b4 85 39 00 00 b6 c0 30  |..Ge...z..9....0|
 00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
 00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
 00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
 000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
 000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
 000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
-000000e0  00 09 00 ff 01 00 00 69  00 0b 00 04 03 00 01 02  |.......i........|
-000000f0  00 0a 00 1c 00 1a 00 17  00 19 00 1c 00 1b 00 18  |................|
-00000100  00 1a 00 16 00 0e 00 0d  00 0b 00 0c 00 09 00 0a  |................|
-00000110  00 23 00 00 00 0d 00 20  00 1e 06 01 06 02 06 03  |.#..... ........|
-00000120  05 01 05 02 05 03 04 01  04 02 04 03 03 01 03 02  |................|
-00000130  03 03 02 01 02 02 02 03  00 0f 00 01 01 00 10 00  |................|
-00000140  10 00 0e 06 70 72 6f 74  6f 32 06 70 72 6f 74 6f  |....proto2.proto|
-00000150  31                                                |1|
+000000e0  00 09 00 ff 02 01 00 00  69 00 0b 00 04 03 00 01  |........i.......|
+000000f0  02 00 0a 00 1c 00 1a 00  17 00 19 00 1c 00 1b 00  |................|
+00000100  18 00 1a 00 16 00 0e 00  0d 00 0b 00 0c 00 09 00  |................|
+00000110  0a 00 23 00 00 00 0d 00  20 00 1e 06 01 06 02 06  |..#..... .......|
+00000120  03 05 01 05 02 05 03 04  01 04 02 04 03 03 01 03  |................|
+00000130  02 03 03 02 01 02 02 02  03 00 0f 00 01 01 00 10  |................|
+00000140  00 10 00 0e 06 70 72 6f  74 6f 32 06 70 72 6f 74  |.....proto2.prot|
+00000150  6f 31                                             |o1|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 35 02 00 00  31 03 03 00 00 00 00 00  |....5...1.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002d0  09 67 fd a7 24 20 3e b2  56 1c ce 97 28 5e f8 2b  |.g..$ >.V...(^.+|
 000002e0  2d 4f 9e f1 07 9f 6c 4b  5b 83 56 e2 32 42 e9 58  |-O....lK[.V.2B.X|
 000002f0  b6 d7 49 a6 b5 68 1a 41  03 56 6b dc 5a 89 05 01  |..I..h.A.Vk.Z...|
-00000300  00 80 36 d2 96 c8 27 66  d8 bd 6c 28 29 30 b3 be  |..6...'f..l()0..|
-00000310  0a bb b2 fe 9d c3 59 47  34 cf de fe f4 ab 5d 79  |......YG4.....]y|
-00000320  24 a9 9d c9 b5 e9 50 6a  3b 96 e3 29 cb d7 37 06  |$.....Pj;..)..7.|
-00000330  19 08 88 15 29 c2 55 03  62 75 1d 35 c2 8e 25 a2  |....).U.bu.5..%.|
-00000340  86 20 bf 18 46 15 81 f2  74 4b bb dd 3d e3 a5 f6  |. ..F...tK..=...|
-00000350  28 18 41 89 c8 39 13 f9  c0 88 fd cc f0 6e 9e 3d  |(.A..9.......n.=|
-00000360  cb 29 ad 26 5b d1 e6 11  5c 64 7d b6 df d7 39 87  |.).&[...\d}...9.|
-00000370  24 df 9f 62 17 ef f2 b3  3a b3 88 a4 f0 91 ea f2  |$..b....:.......|
-00000380  5d c9 16 03 03 00 04 0e  00 00 00                 |]..........|
+00000300  00 80 97 89 a3 7f 30 d1  7b 70 26 3d a4 d5 66 2e  |......0.{p&=..f.|
+00000310  cd fc 02 f5 37 a5 cd 09  69 7a c6 2f b2 62 e8 a6  |....7...iz./.b..|
+00000320  88 e2 3a c4 0a 8c 77 ad  d3 c9 29 49 84 81 9c cd  |..:...w...)I....|
+00000330  33 44 59 2d b5 2e e7 ce  12 c5 3b 46 13 6d 4a c8  |3DY-......;F.mJ.|
+00000340  6d f6 1f e7 f1 99 13 01  ca 43 79 fa b5 78 c7 1a  |m........Cy..x..|
+00000350  7d 8f 85 dd 3b ca 56 22  c3 d0 41 11 1b 13 8c 07  |}...;.V"..A.....|
+00000360  02 75 87 7a ea 68 43 30  0b 2a 38 52 b2 8f cc ea  |.u.z.hC0.*8R....|
+00000370  a3 a3 cb 71 fb 97 cd 3e  74 d0 5b 9b bd 17 13 f0  |...q...>t.[.....|
+00000380  d9 fe 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 b0 22 15 73 fc  |....F...BA..".s.|
-00000010  1c fd 24 4a 36 69 8a be  ac bd 72 30 bb 6b e1 9b  |..$J6i....r0.k..|
-00000020  42 e8 56 7a 86 b1 8d cb  9c 3e 2d 63 13 57 a8 13  |B.Vz.....>-c.W..|
-00000030  71 3b a2 01 86 af f8 76  40 0b 44 4f 0a 0f 5a da  |q;.....v@.DO..Z.|
-00000040  31 36 3b 13 c0 10 6c 96  64 a7 24 14 03 03 00 01  |16;...l.d.$.....|
-00000050  01 16 03 03 00 28 10 2d  45 93 5c 37 34 d9 2a a0  |.....(.-E.\74.*.|
-00000060  b6 37 13 bc a6 1f 0c ce  2e 55 c1 ad 36 b8 60 72  |.7.......U..6.`r|
-00000070  81 cb 1a 7a 5b 26 49 ad  77 ef 62 e8 fc 00        |...z[&I.w.b...|
+00000000  16 03 03 00 46 10 00 00  42 41 04 ba 5b 0f e7 ec  |....F...BA..[...|
+00000010  8e c8 ad 51 8c c0 50 f1  8a 2a 68 32 74 d0 95 03  |...Q..P..*h2t...|
+00000020  0c 61 f1 1c 89 ed 95 5d  9a 4a 14 ee cc 14 9a 73  |.a.....].J.....s|
+00000030  f6 db 46 dd b7 47 8a 82  3d 7a b8 9f 45 d1 a2 3f  |..F..G..=z..E..?|
+00000040  f4 34 9b b6 6d 7d 41 87  c9 d5 cd 14 03 03 00 01  |.4..m}A.........|
+00000050  01 16 03 03 00 28 1e ae  f6 90 a9 91 eb 4b ca 23  |.....(.......K.#|
+00000060  6e bf 9e 67 5b 38 ab f6  d6 ee 12 aa b9 b6 d0 6e  |n..g[8.........n|
+00000070  a7 dd 45 91 34 45 78 a0  04 9e d8 85 48 48        |..E.4Ex.....HH|
 >>> Flow 4 (server to client)
 00000000  16 03 03 00 82 04 00 00  7e 00 00 00 00 00 78 50  |........~.....xP|
 00000010  46 ad c1 db a8 38 86 7b  2b bb fd d0 c3 42 3e 00  |F....8.{+....B>.|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 94  |................|
-00000030  6f ec 80 83 61 05 33 d2  9d 95 89 7b 28 54 50 50  |o...a.3....{(TPP|
-00000040  b3 3c 99 5c 82 ab cf 88  24 e8 48 81 db 4a 22 79  |.<.\....$.H..J"y|
-00000050  0b fa 33 50 ed 82 a1 7c  33 0e f2 ff 6d a7 d6 88  |..3P...|3...m...|
-00000060  29 65 74 e3 27 33 94 97  66 0c 86 ce fc ca 0e 2a  |)et.'3..f......*|
-00000070  96 fa fe 19 a3 01 64 d9  4d 8e 58 95 5b 74 a6 aa  |......d.M.X.[t..|
-00000080  f4 9f c1 34 97 2d e5 14  03 03 00 01 01 16 03 03  |...4.-..........|
-00000090  00 28 00 00 00 00 00 00  00 00 4d 56 6d d5 6f cc  |.(........MVm.o.|
-000000a0  3d d4 85 32 3c 07 ea 3c  52 61 88 8e dd d5 d3 d0  |=..2<..<Ra......|
-000000b0  f9 4e 1b b1 c1 d1 67 cb  1a e8 17 03 03 00 25 00  |.N....g.......%.|
-000000c0  00 00 00 00 00 00 01 c3  43 ab 0c ab 59 30 e9 d4  |........C...Y0..|
-000000d0  eb 65 c2 7f 9a 5a 1e 09  06 a4 9d 69 bb 3f 0b 06  |.e...Z.....i.?..|
-000000e0  87 b8 09 39 15 03 03 00  1a 00 00 00 00 00 00 00  |...9............|
-000000f0  02 c2 6f f4 88 f0 7a 59  a6 49 3e 44 a3 7b 6e 36  |..o...zY.I>D.{n6|
-00000100  ae 66 87                                          |.f.|
+00000030  6f ec 80 83 61 4f 7f 09  64 32 96 26 b5 71 46 6a  |o...aO..d2.&.qFj|
+00000040  29 7d fd 0b bb 49 13 0e  c8 c5 de 06 ed 47 e8 cb  |)}...I.......G..|
+00000050  d8 9f 18 82 69 af ab 24  d2 78 90 ba 9a c8 24 95  |....i..$.x....$.|
+00000060  46 53 19 2e e8 33 94 3c  22 73 26 d6 86 4e 01 a4  |FS...3.<"s&..N..|
+00000070  34 ea a8 bf f2 ca b5 0d  fc f6 08 b9 31 b3 42 e7  |4...........1.B.|
+00000080  c1 92 96 f9 bf 9a 00 14  03 03 00 01 01 16 03 03  |................|
+00000090  00 28 00 00 00 00 00 00  00 00 bd 51 1d 0e bd 51  |.(.........Q...Q|
+000000a0  a3 b1 03 f2 df f4 ba 9b  1e a5 a8 22 e7 ce 7c 19  |..........."..|.|
+000000b0  1a bf 37 3d 42 f4 4d 6f  63 75 17 03 03 00 25 00  |..7=B.Mocu....%.|
+000000c0  00 00 00 00 00 00 01 52  8a d2 34 52 70 f1 cf 87  |.......R..4Rp...|
+000000d0  54 4e fd e6 11 a7 76 1a  f4 7b 70 e8 34 ef 01 c8  |TN....v..{p.4...|
+000000e0  6c 4a f8 6d 15 03 03 00  1a 00 00 00 00 00 00 00  |lJ.m............|
+000000f0  02 8a 4c f9 7c d1 61 a6  cd 2a e6 3a 5b b0 cb aa  |..L.|.a..*.:[...|
+00000100  91 2e 8b                                          |...|
index 344d9737b253cc83cbc7800b76799f843f9f26f6..ae3748f49bfcf115e1a8258c9094c3b57a748a5a 100644 (file)
@@ -1,7 +1,7 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 01 34 01 00 01  30 03 03 78 08 b2 d4 18  |....4...0..x....|
-00000010  8e b1 6b a2 d2 e0 c6 41  02 c5 93 f1 b9 60 94 e8  |..k....A.....`..|
-00000020  f2 64 6c 97 50 2d 24 a3  cd c0 36 00 00 b6 c0 30  |.dl.P-$...6....0|
+00000000  16 03 01 01 35 01 00 01  31 03 03 00 02 67 8e 1d  |....5...1....g..|
+00000010  3b d2 26 20 63 c5 6a b6  68 25 02 72 ce 86 6b c7  |;.& c.j.h%.r..k.|
+00000020  97 1a 9f 4d be 02 98 ac  24 5e 82 00 00 b6 c0 30  |...M....$^.....0|
 00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
 00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
 00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
 000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
 000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
 000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
-000000e0  00 09 00 ff 01 00 00 51  00 0b 00 04 03 00 01 02  |.......Q........|
-000000f0  00 0a 00 1c 00 1a 00 17  00 19 00 1c 00 1b 00 18  |................|
-00000100  00 1a 00 16 00 0e 00 0d  00 0b 00 0c 00 09 00 0a  |................|
-00000110  00 0d 00 20 00 1e 06 01  06 02 06 03 05 01 05 02  |... ............|
-00000120  05 03 04 01 04 02 04 03  03 01 03 02 03 03 02 01  |................|
-00000130  02 02 02 03 00 0f 00 01  01                       |.........|
+000000e0  00 09 00 ff 02 01 00 00  51 00 0b 00 04 03 00 01  |........Q.......|
+000000f0  02 00 0a 00 1c 00 1a 00  17 00 19 00 1c 00 1b 00  |................|
+00000100  18 00 1a 00 16 00 0e 00  0d 00 0b 00 0c 00 09 00  |................|
+00000110  0a 00 0d 00 20 00 1e 06  01 06 02 06 03 05 01 05  |.... ...........|
+00000120  02 05 03 04 01 04 02 04  03 03 01 03 02 03 03 02  |................|
+00000130  01 02 02 02 03 00 0f 00  01 01                    |..........|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 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 05  03 00 8b 30 81 88 02 42  |A.Vk.Z.....0...B|
-000002a0  00 91 b4 4a f2 9d 13 a1  6d 3b ee 46 2f 3b 97 50  |...J....m;.F/;.P|
-000002b0  b9 3e 28 7a 51 7a 8b 3b  a6 16 03 d6 1f 92 0a ec  |.>(zQz.;........|
-000002c0  5b 9b b5 48 98 ce d8 22  bd 7d eb cb 14 7b 14 73  |[..H...".}...{.s|
-000002d0  2d 5f 01 8c dc 5a 63 34  92 4e 59 4a 90 f9 b1 c9  |-_...Zc4.NYJ....|
-000002e0  d8 18 02 42 01 89 e4 e4  39 d0 52 d1 70 19 fe d7  |...B....9.R.p...|
-000002f0  c6 70 10 36 94 1e 45 fd  b4 03 37 79 c7 db cf 6d  |.p.6..E...7y...m|
-00000300  33 5d 80 fe 04 de d1 78  bf c4 dd cf 91 82 57 14  |3].....x......W.|
-00000310  14 09 e3 2d dd d2 78 9c  53 cc 1f f7 40 6c 4a 59  |...-..x.S...@lJY|
-00000320  49 a8 a1 06 24 18 16 03  03 00 04 0e 00 00 00     |I...$..........|
+000002a0  01 bc 56 16 22 ad fd e7  ac ba c8 f5 3f c0 d7 f8  |..V.".......?...|
+000002b0  8c 64 e0 ba 09 30 c3 66  49 90 7e d2 68 86 07 72  |.d...0.fI.~.h..r|
+000002c0  20 87 a1 e1 36 92 a7 68  e2 c3 6e 34 93 a9 ca e8  | ...6..h..n4....|
+000002d0  68 3d 9e 42 c4 1e 8e 2d  95 05 ee a6 a4 2c 8d be  |h=.B...-.....,..|
+000002e0  e3 88 02 42 01 16 18 77  b9 99 0e f8 46 90 46 07  |...B...w....F.F.|
+000002f0  f9 67 a9 26 68 d7 da c8  a1 d9 67 55 ec 37 11 2d  |.g.&h.....gU.7.-|
+00000300  4b f3 52 f4 96 6a 0e 8a  6a 14 21 94 63 ea f9 70  |K.R..j..j.!.c..p|
+00000310  2d 57 05 8a 72 29 6e d2  60 a1 97 af 08 5b c3 cf  |-W..r)n.`....[..|
+00000320  3a 82 a3 81 11 cf 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 66 37 3a ce 68  |....F...BA.f7:.h|
-00000010  23 0f b2 d0 cb 20 24 26  37 d5 84 46 4a 2e 59 80  |#.... $&7..FJ.Y.|
-00000020  87 b3 10 7e 36 fd af 7c  99 07 99 dd 18 af 6d 7c  |...~6..|......m||
-00000030  b5 b2 b7 93 45 95 d9 98  1a 13 5b a2 12 e8 b7 95  |....E.....[.....|
-00000040  ed a1 3a 6d aa 8f fc b6  b5 b4 41 14 03 03 00 01  |..:m......A.....|
-00000050  01 16 03 03 00 40 b0 12  69 00 a4 3a 6d bd 56 40  |.....@..i..:m.V@|
-00000060  6e 9d 5e a8 1b 0f 59 c5  09 48 b2 07 d8 bc 7b 02  |n.^...Y..H....{.|
-00000070  70 61 f6 1b a9 27 55 8c  16 4d 69 4c ca 31 30 9f  |pa...'U..MiL.10.|
-00000080  d3 62 ba d4 1b 11 ee 0a  a0 f3 61 be c6 64 c3 dc  |.b........a..d..|
-00000090  97 50 47 27 ed 09                                 |.PG'..|
+00000000  16 03 03 00 46 10 00 00  42 41 04 8c 80 0c da 24  |....F...BA.....$|
+00000010  d6 66 ff cc 1b 26 d5 3f  37 37 16 8f 16 ee 0d 5f  |.f...&.?77....._|
+00000020  c3 0e 62 7c e4 52 2d 43  29 e9 6b da 49 bc 99 16  |..b|.R-C).k.I...|
+00000030  28 46 8e 43 20 7f 12 66  1c 94 1c 03 55 6f 05 53  |(F.C ..f....Uo.S|
+00000040  6f b7 dc 8b 70 9d 9d c5  1f da 5b 14 03 03 00 01  |o...p.....[.....|
+00000050  01 16 03 03 00 40 17 60  dd e5 b2 58 fd 74 10 38  |.....@.`...X.t.8|
+00000060  95 b1 73 7e 8f 7a 2b d0  f5 65 80 0c dc b1 ca 29  |..s~.z+..e.....)|
+00000070  06 25 e1 f9 c3 c0 7c 88  e4 ad d3 16 0a 8a dd 1f  |.%....|.........|
+00000080  a7 86 86 0f ac c7 ea f5  0f 1f 2b 97 85 b3 81 f7  |..........+.....|
+00000090  5d 42 2f 3b 72 80                                 |]B/;r.|
 >>> 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 09 34 9a eb 7c  |............4..||
-00000020  6a 6d 6a 02 7b 50 14 b8  f7 b0 93 30 ea 0b 61 4a  |jmj.{P.....0..aJ|
-00000030  0b 75 10 39 41 78 46 9d  ba 8e d3 e9 e4 ab dc 1f  |.u.9AxF.........|
-00000040  c9 43 95 e8 f9 d6 3a d3  5d 7d 09 17 03 03 00 40  |.C....:.]}.....@|
+00000010  00 00 00 00 00 00 00 00  00 00 00 82 01 fd 38 ae  |..............8.|
+00000020  a4 07 8f bd 72 0a a2 b5  c5 78 09 89 65 1b 6d 1e  |....r....x..e.m.|
+00000030  56 52 9d 4f de 02 15 2d  93 d8 8f d7 1f bb 07 3b  |VR.O...-.......;|
+00000040  e9 62 3c 19 3e 19 65 ac  10 aa e5 17 03 03 00 40  |.b<.>.e........@|
 00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000060  b4 64 88 d5 53 f9 1e 47  d4 d8 c4 fa 0e c2 76 a6  |.d..S..G......v.|
-00000070  ed 5c 17 ba ea 76 72 cb  c5 73 a3 c5 44 21 3c 40  |.\...vr..s..D!<@|
-00000080  33 27 09 37 73 3b 0e a3  7b 95 72 10 8d 74 85 19  |3'.7s;..{.r..t..|
+00000060  18 61 1d 26 f3 b9 34 20  00 6c 27 75 fc 35 f5 c2  |.a.&..4 .l'u.5..|
+00000070  6f 71 ca 9b 0d 70 30 46  57 7c 07 86 7d 52 a9 d6  |oq...p0FW|..}R..|
+00000080  ab fc 89 a5 48 79 ae 60  03 05 4b 17 b2 d9 6b 39  |....Hy.`..K...k9|
 00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-000000a0  00 00 00 00 00 b3 c0 05  e9 ec 05 06 52 ef 09 b7  |............R...|
-000000b0  52 29 04 88 ed 11 bb bd  36 a3 0f ce 2c 55 a2 87  |R)......6...,U..|
-000000c0  7e 2b 0c aa 83                                    |~+...|
+000000a0  00 00 00 00 00 8f 8d 88  88 c5 1e f5 bf 06 f2 45  |...............E|
+000000b0  e7 fe f0 24 c7 4c 92 5a  80 a7 89 c8 2b ac 49 d9  |...$.L.Z....+.I.|
+000000c0  39 00 ca 57 ec                                    |9..W.|
index 10624c02591a528cb9b81757a098ad1b9c0bc6bf..144ef4288a35b3a669eff57dc83aad4fd49f46fb 100644 (file)
@@ -1,7 +1,7 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 01 34 01 00 01  30 03 03 10 5e c8 3f c6  |....4...0...^.?.|
-00000010  fe 44 c4 f0 13 c5 bd ad  06 21 65 e5 a8 40 b5 1d  |.D.......!e..@..|
-00000020  21 07 99 34 5b ef 70 85  29 92 7d 00 00 b6 c0 30  |!..4[.p.).}....0|
+00000000  16 03 01 01 35 01 00 01  31 03 03 ed 84 e2 1a c1  |....5...1.......|
+00000010  d9 3f a5 ba 70 0b 5f 3f  3b 87 79 18 27 03 92 ee  |.?..p._?;.y.'...|
+00000020  b1 9f c7 36 26 e3 0b 6d  fc d5 ed 00 00 b6 c0 30  |...6&..m.......0|
 00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
 00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
 00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
 000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
 000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
 000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
-000000e0  00 09 00 ff 01 00 00 51  00 0b 00 04 03 00 01 02  |.......Q........|
-000000f0  00 0a 00 1c 00 1a 00 17  00 19 00 1c 00 1b 00 18  |................|
-00000100  00 1a 00 16 00 0e 00 0d  00 0b 00 0c 00 09 00 0a  |................|
-00000110  00 0d 00 20 00 1e 06 01  06 02 06 03 05 01 05 02  |... ............|
-00000120  05 03 04 01 04 02 04 03  03 01 03 02 03 03 02 01  |................|
-00000130  02 02 02 03 00 0f 00 01  01                       |.........|
+000000e0  00 09 00 ff 02 01 00 00  51 00 0b 00 04 03 00 01  |........Q.......|
+000000f0  02 00 0a 00 1c 00 1a 00  17 00 19 00 1c 00 1b 00  |................|
+00000100  18 00 1a 00 16 00 0e 00  0d 00 0b 00 0c 00 09 00  |................|
+00000110  0a 00 0d 00 20 00 1e 06  01 06 02 06 03 05 01 05  |.... ...........|
+00000120  02 05 03 04 01 04 02 04  03 03 01 03 02 03 03 02  |................|
+00000130  01 02 02 02 03 00 0f 00  01 01                    |..........|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002c0  51 88 35 75 71 b5 e5 54  5b 12 2e 8f 09 67 fd a7  |Q.5uq..T[....g..|
 000002d0  24 20 3e b2 56 1c ce 97  28 5e f8 2b 2d 4f 9e f1  |$ >.V...(^.+-O..|
 000002e0  07 9f 6c 4b 5b 83 56 e2  32 42 e9 58 b6 d7 49 a6  |..lK[.V.2B.X..I.|
-000002f0  b5 68 1a 41 03 56 6b dc  5a 89 05 01 00 80 6a 4b  |.h.A.Vk.Z.....jK|
-00000300  b1 7d 23 cd 0e cb 26 02  d4 ee 90 f2 e0 4a 47 3d  |.}#...&......JG=|
-00000310  b3 36 90 8d 01 42 98 92  ad 75 87 71 02 70 02 a8  |.6...B...u.q.p..|
-00000320  0c b0 06 ee bd 6a 1f 3f  6c 4b 4b 6b 75 41 23 b4  |.....j.?lKKkuA#.|
-00000330  f9 c2 a6 60 e2 de 55 b6  d4 85 62 e9 8f 20 70 ed  |...`..U...b.. p.|
-00000340  9a b8 bb dd 1f 19 87 e9  ad b3 30 3f 7c 63 51 f1  |..........0?|cQ.|
-00000350  59 ab d1 a0 a1 80 22 56  ca 68 52 f8 0f 80 c6 a6  |Y....."V.hR.....|
-00000360  9e 12 51 ed 29 d0 6d c2  1a e5 37 dc 76 e3 f3 53  |..Q.).m...7.v..S|
-00000370  1b 07 0b ea a6 11 af dc  54 d3 ee 25 cc 27 16 03  |........T..%.'..|
+000002f0  b5 68 1a 41 03 56 6b dc  5a 89 05 01 00 80 7c 5c  |.h.A.Vk.Z.....|\|
+00000300  f6 68 cc 07 f0 bd ec 30  07 d0 70 1b c6 95 a4 14  |.h.....0..p.....|
+00000310  67 3a 83 a1 43 ff 0a c3  f0 b7 ee 59 f8 c7 09 65  |g:..C......Y...e|
+00000320  08 ac 18 34 d4 8f 46 c4  2c 91 7b 57 95 e0 54 03  |...4..F.,.{W..T.|
+00000330  d8 8e b6 53 61 74 77 8b  a3 5f 23 f0 06 dc 3a 56  |...Satw.._#...:V|
+00000340  61 80 5e 31 d5 75 c3 05  9f d0 06 1f c5 32 ba 79  |a.^1.u.......2.y|
+00000350  fd 14 a9 54 5a 18 b4 2b  09 0e 19 ab 76 0b 12 5d  |...TZ..+....v..]|
+00000360  52 27 ce b8 dd 4c f8 f2  d2 70 56 43 19 53 b3 13  |R'...L...pVC.S..|
+00000370  b9 b7 65 ce cd 50 ed 4a  9f 42 96 c7 3c b9 16 03  |..e..P.J.B..<...|
 00000380  03 00 04 0e 00 00 00                              |.......|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 2d 4b 0c 6b 65  |....F...BA.-K.ke|
-00000010  82 32 95 8b 77 ec f0 f2  b2 ba d1 38 74 ed 82 49  |.2..w......8t..I|
-00000020  fb ce 8f 66 97 9d b6 97  d8 ae f5 19 af ad 47 b9  |...f..........G.|
-00000030  db 7b d2 c9 4e 10 68 14  ed 23 a5 98 94 f9 2a 00  |.{..N.h..#....*.|
-00000040  b6 44 b3 44 01 29 6c 56  da bb a8 14 03 03 00 01  |.D.D.)lV........|
-00000050  01 16 03 03 00 40 f4 fd  de d6 20 2e 18 80 4e 73  |.....@.... ...Ns|
-00000060  af dd 97 42 08 3b 51 80  e9 26 00 48 6b 8b 21 99  |...B.;Q..&.Hk.!.|
-00000070  a8 60 1f 64 51 d0 5a 90  8b b0 69 b8 6b 29 59 21  |.`.dQ.Z...i.k)Y!|
-00000080  b1 13 19 13 07 01 e1 2c  c3 6b 17 2d 01 a5 be d6  |.......,.k.-....|
-00000090  b0 0d 3d 6a 8c fe                                 |..=j..|
+00000000  16 03 03 00 46 10 00 00  42 41 04 36 1c 6c f5 0a  |....F...BA.6.l..|
+00000010  7f 52 84 ac 5a 27 45 76  79 a6 89 f1 1d d9 30 30  |.R..Z'Evy.....00|
+00000020  b6 64 af c7 34 11 12 b3  b9 72 83 e6 78 bc 06 74  |.d..4....r..x..t|
+00000030  a7 a4 10 01 34 77 5c 05  88 82 0f a9 cf 8d e8 68  |....4w\........h|
+00000040  09 80 c7 79 b6 e9 5a 2a  5f 80 5e 14 03 03 00 01  |...y..Z*_.^.....|
+00000050  01 16 03 03 00 40 ef f9  3c 34 cd 26 70 c9 7b 60  |.....@..<4.&p.{`|
+00000060  a7 27 0a 2b 86 18 2f 10  ad 48 3f 2e 9e 88 13 d6  |.'.+../..H?.....|
+00000070  d8 c6 fd 35 99 be 09 e6  dd ae 02 06 ea df 60 62  |...5..........`b|
+00000080  e0 f8 67 ea 9d c8 8c 11  d8 5a e7 6a a6 b2 eb 62  |..g......Z.j...b|
+00000090  23 b2 d2 be 75 58                                 |#...uX|
 >>> 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 84 e2 7f e3 b4  |................|
-00000020  53 d7 d0 30 c4 e5 ea 09  df ba 33 b0 02 34 eb 2e  |S..0......3..4..|
-00000030  b2 ec 47 0d e7 20 76 12  fa 53 3b 44 86 e1 e1 63  |..G.. v..S;D...c|
-00000040  06 29 57 98 ce 87 18 ad  02 17 01 17 03 03 00 40  |.)W............@|
+00000010  00 00 00 00 00 00 00 00  00 00 00 a6 52 02 4f 20  |............R.O |
+00000020  f6 d7 2d 2d 7c 65 4e 7b  43 33 32 50 9b c6 68 2c  |..--|eN{C32P..h,|
+00000030  c0 6a 02 6f c6 bc 38 d8  06 c0 42 ba c1 41 ce 5c  |.j.o..8...B..A.\|
+00000040  d0 a0 5f fc 8a 31 33 26  a2 79 9a 17 03 03 00 40  |.._..13&.y.....@|
 00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000060  b0 3a f5 90 90 30 9c b3  39 5b b4 56 f6 b9 30 7e  |.:...0..9[.V..0~|
-00000070  8e a8 2d 60 47 b6 57 8a  20 61 02 f2 8e 43 c2 01  |..-`G.W. a...C..|
-00000080  ee f0 be 5a 93 52 2f ea  03 2a 4f 01 ea 9e 1c a2  |...Z.R/..*O.....|
+00000060  f2 42 8f e8 79 0d f3 c0  a0 b7 8a 5e de b8 52 c4  |.B..y......^..R.|
+00000070  b6 9d b2 10 00 e8 a3 19  27 12 ac 38 e7 d8 ec 89  |........'..8....|
+00000080  af 7d 68 15 03 e8 c4 c8  08 34 ad ad 15 7b 69 bb  |.}h......4...{i.|
 00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-000000a0  00 00 00 00 00 c0 7e 61  51 a1 76 15 8a 7e 20 5f  |......~aQ.v..~ _|
-000000b0  d4 a4 c6 3e 6c 50 18 c6  63 88 d0 ac 4c fa 31 b3  |...>lP..c...L.1.|
-000000c0  e7 c9 77 11 7a                                    |..w.z|
+000000a0  00 00 00 00 00 a0 a5 02  ff b1 77 9a 8f e0 fc ca  |..........w.....|
+000000b0  86 ee ca 9c 7c 3b ca 61  33 7f f9 12 54 79 41 97  |....|;.a3...TyA.|
+000000c0  b0 7d bd 9b 93                                    |.}...|
index 56c3c822e352124fafd8a0f47e53f75d6e01ab3d..626024cb2bc1ca3de982b03efd9a1408a185a528 100644 (file)
@@ -1,10 +1,10 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5a 01 00 00  56 03 03 80 13 c8 83 43  |....Z...V......C|
-00000010  94 79 15 01 6e 0a 9f c5  0f e7 f6 d8 b1 94 de b4  |.y..n...........|
-00000020  57 8c 4f a8 08 48 ee 9b  b4 d2 43 00 00 04 00 05  |W.O..H....C.....|
-00000030  00 ff 01 00 00 29 00 0d  00 20 00 1e 06 01 06 02  |.....)... ......|
-00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000050  03 02 03 03 02 01 02 02  02 03 00 0f 00 01 01     |...............|
+00000000  16 03 01 00 5b 01 00 00  57 03 03 55 46 9e 3b 51  |....[...W..UF.;Q|
+00000010  e7 cd bf df bc fe 0d 5a  5a de a6 09 6c 72 cb ea  |.......ZZ...lr..|
+00000020  ab f8 a6 fd 9a 5b be 77  7d 25 20 00 00 04 00 05  |.....[.w}% .....|
+00000030  00 ff 02 01 00 00 29 00  0d 00 20 00 1e 06 01 06  |......)... .....|
+00000040  02 06 03 05 01 05 02 05  03 04 01 04 02 04 03 03  |................|
+00000050  01 03 02 03 03 02 01 02  02 02 03 00 0f 00 01 01  |................|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000001e0  be e8 91 b3 da 1a f5 5d  a3 23 f5 26 8b 45 70 8d  |.......].#.&.Ep.|
 000001f0  65 62 9b 7e 01 99 3d 18  f6 10 9a 38 61 9b 2e 57  |eb.~..=....8a..W|
 00000200  e4 fa cc b1 8a ce e2 23  a0 87 f0 e1 67 51 eb 16  |.......#....gQ..|
-00000210  03 03 00 86 10 00 00 82  00 80 88 00 24 23 a5 c7  |............$#..|
-00000220  03 2d 86 37 91 f1 71 a9  5f fb 97 49 88 04 9b 0e  |.-.7..q._..I....|
-00000230  89 da 65 d0 56 71 e7 76  22 ef 8e 11 0e 6b 50 3d  |..e.Vq.v"....kP=|
-00000240  64 3f f7 9b e4 45 01 d9  12 cb da fe 10 da 4e b5  |d?...E........N.|
-00000250  b8 6a b5 bc 74 19 d3 4f  a9 bb ee 54 37 e4 70 d0  |.j..t..O...T7.p.|
-00000260  b6 e7 35 96 70 fe a5 2b  14 ac fb c6 1a fa 7d 12  |..5.p..+......}.|
-00000270  87 1b 63 9d 72 30 4d 2c  1a c9 29 32 72 b6 13 53  |..c.r0M,..)2r..S|
-00000280  96 05 de 78 bc f0 1a 74  e2 31 b9 ea db 62 62 6e  |...x...t.1...bbn|
-00000290  a0 a6 b2 c0 3e 2a 94 0d  6a f7 16 03 03 00 92 0f  |....>*..j.......|
-000002a0  00 00 8e 04 03 00 8a 30  81 87 02 42 01 71 5b 3b  |.......0...B.q[;|
-000002b0  a3 35 58 c0 b6 08 09 4f  ac af 89 e0 b3 d5 3d 45  |.5X....O......=E|
-000002c0  1f 49 7f 4a c9 bc 9d 0e  50 3a f5 79 bc 54 5d a9  |.I.J....P:.y.T].|
-000002d0  62 ed 85 c5 f3 47 36 03  cc f1 cd 33 c3 70 2a a6  |b....G6....3.p*.|
-000002e0  7c d9 6e 0c db 0d 1b 4f  6a 39 ba 77 bd ea 02 41  ||.n....Oj9.w...A|
-000002f0  00 f2 b7 06 df 2f 81 7e  98 24 46 06 59 4e 86 6a  |...../.~.$F.YN.j|
-00000300  b7 4f b6 4b 95 40 88 f0  8f f8 bd 16 f5 d5 82 7e  |.O.K.@.........~|
-00000310  82 51 6f 05 49 43 59 cd  1d 40 69 67 ff 65 a8 68  |.Qo.ICY..@ig.e.h|
-00000320  39 2f a1 ad a7 6a ef 5c  d5 69 5e 16 50 bb 2a b2  |9/...j.\.i^.P.*.|
-00000330  2f 14 03 03 00 01 01 16  03 03 00 24 55 f6 74 21  |/..........$U.t!|
-00000340  b4 08 a0 7f a2 dc 86 44  e3 f8 e3 0d e1 d6 5c 1c  |.......D......\.|
-00000350  22 1e 41 2b 30 cc 34 0f  a4 a1 7c a0 27 21 01 e0  |".A+0.4...|.'!..|
+00000210  03 03 00 86 10 00 00 82  00 80 03 64 6f 74 1b 0e  |...........dot..|
+00000220  df 6b a4 8e f8 ec b5 02  c2 d6 7a 9a f3 bf 3e 32  |.k........z...>2|
+00000230  ba 41 dd 61 33 8a 63 fb  71 e6 87 68 32 9c 41 d5  |.A.a3.c.q..h2.A.|
+00000240  59 ee 93 55 16 e9 0a 01  72 14 93 23 82 73 91 3a  |Y..U....r..#.s.:|
+00000250  6d 3c e6 e0 a8 33 34 84  80 59 65 6b c1 6d 01 19  |m<...34..Yek.m..|
+00000260  cc d5 4f 1d f6 88 4f cc  b5 c6 3c 9c 68 4a be 47  |..O...O...<.hJ.G|
+00000270  c2 67 61 a4 e3 c3 00 c0  9c d4 83 ed b5 65 25 a4  |.ga..........e%.|
+00000280  2e 1c 8d 47 3f 80 b8 1d  5b 74 a2 bf fa b9 b7 e2  |...G?...[t......|
+00000290  58 94 ba ec a9 cf 1c 56  ef 0a 16 03 03 00 92 0f  |X......V........|
+000002a0  00 00 8e 04 03 00 8a 30  81 87 02 41 75 cf 19 3a  |.......0...Au..:|
+000002b0  a1 9e e9 69 c7 f3 63 0b  46 c2 60 35 e1 cc 95 0d  |...i..c.F.`5....|
+000002c0  ee 0f ad 28 17 b4 b2 09  ea 38 18 c7 08 84 b6 ac  |...(.....8......|
+000002d0  65 03 b9 49 c3 ea ff e4  45 d3 15 14 3a 94 14 0c  |e..I....E...:...|
+000002e0  cb 48 ce 75 c2 a4 4a 0e  7d d8 f0 c5 5f 02 42 01  |.H.u..J.}..._.B.|
+000002f0  99 dd c7 54 ce ee 38 bb  18 16 eb 92 0a 53 0b 92  |...T..8......S..|
+00000300  d8 73 73 48 b3 0a 3b ea  12 ea 62 d3 88 99 00 54  |.ssH..;...b....T|
+00000310  bc 92 28 7d 66 b3 17 7f  e7 5f 69 50 d1 a1 4c 6a  |..(}f...._iP..Lj|
+00000320  99 60 00 59 0a 4d 6c 97  05 54 ee 82 5a e1 c5 88  |.`.Y.Ml..T..Z...|
+00000330  1b 14 03 03 00 01 01 16  03 03 00 24 80 64 11 aa  |...........$.d..|
+00000340  cc 9d 1c 83 b6 2f 56 dc  48 cb 33 e5 0f 25 a2 42  |...../V.H.3..%.B|
+00000350  df b8 a6 cc 64 93 10 63  ad 76 91 27 3f c7 8f d4  |....d..c.v.'?...|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 6f 6b e7 fb f7  |..........$ok...|
-00000010  52 83 b3 6f ba 1b d7 e8  cb 0a 05 ee 90 04 2b c7  |R..o..........+.|
-00000020  c2 bd 0d 8e ee 42 88 40  ae 01 4a d0 07 4b f4 17  |.....B.@..J..K..|
-00000030  03 03 00 21 e0 8b bd 80  04 18 9c be 12 07 d4 4d  |...!...........M|
-00000040  58 d9 ec c3 f0 67 b5 b3  d1 78 25 e7 2e dd a0 0a  |X....g...x%.....|
-00000050  ac 0f a1 90 59 15 03 03  00 16 76 30 22 0b 00 83  |....Y.....v0"...|
-00000060  c4 31 29 1c ca 44 cb 9f  0e 48 17 21 43 f6 af 47  |.1)..D...H.!C..G|
+00000000  14 03 03 00 01 01 16 03  03 00 24 24 8d e5 5f d9  |..........$$.._.|
+00000010  99 7d d4 f2 5f f4 4b e3  b4 8e 33 84 7a c3 cb bf  |.}.._.K...3.z...|
+00000020  21 00 94 db 7b 7f 6c fa  a0 f2 9f 0e e9 3b 27 17  |!...{.l......;'.|
+00000030  03 03 00 21 67 f8 3a ff  c1 3b cb de 04 bf 49 a6  |...!g.:..;....I.|
+00000040  9a 45 56 ab 64 99 06 7e  40 cc a7 f6 4e 1e ca cb  |.EV.d..~@...N...|
+00000050  11 87 da 58 b7 15 03 03  00 16 10 1b 62 97 25 bf  |...X........b.%.|
+00000060  84 c1 23 d6 76 4a a1 da  07 c7 25 68 f6 6e 63 55  |..#.vJ....%h.ncU|
index 862e0be09eef947abc0d13095bd128d71bce7a30..819825ca8972a98660a5f780ef5fceb3d34c726a 100644 (file)
@@ -1,10 +1,10 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5a 01 00 00  56 03 03 b0 80 f6 7c 13  |....Z...V.....|.|
-00000010  30 5d 57 f0 11 3b 30 4b  0e 01 50 9a 44 0b 89 6f  |0]W..;0K..P.D..o|
-00000020  b6 f1 a3 34 b4 f1 b9 bf  fe 66 a5 00 00 04 00 05  |...4.....f......|
-00000030  00 ff 01 00 00 29 00 0d  00 20 00 1e 06 01 06 02  |.....)... ......|
-00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000050  03 02 03 03 02 01 02 02  02 03 00 0f 00 01 01     |...............|
+00000000  16 03 01 00 5b 01 00 00  57 03 03 87 41 6f c5 67  |....[...W...Ao.g|
+00000010  07 3b 12 46 ad aa d2 be  0d 08 98 e3 c7 4b ac 48  |.;.F.........K.H|
+00000020  67 02 6b 3b dc 84 79 c5  57 e9 89 00 00 04 00 05  |g.k;..y.W.......|
+00000030  00 ff 02 01 00 00 29 00  0d 00 20 00 1e 06 01 06  |......)... .....|
+00000040  02 06 03 05 01 05 02 05  03 04 01 04 02 04 03 03  |................|
+00000050  01 03 02 03 03 02 01 02  02 02 03 00 0f 00 01 01  |................|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000001d0  8b ec ab 67 be c8 64 b0  11 50 46 58 17 6b 99 1c  |...g..d..PFX.k..|
 000001e0  d3 1d fc 06 f1 0e e5 96  a8 0c f9 78 20 b7 44 18  |...........x .D.|
 000001f0  51 8d 10 7e 4f 94 67 df  a3 4e 70 73 8e 90 91 85  |Q..~O.g..Nps....|
-00000200  16 03 03 00 86 10 00 00  82 00 80 98 61 16 34 c4  |............a.4.|
-00000210  c6 0a 47 c1 de 87 b1 b7  70 1b 24 8d 7e 35 90 35  |..G.....p.$.~5.5|
-00000220  f7 a5 6f c7 c9 91 ad 46  4c 50 e5 7e 61 7c 49 66  |..o....FLP.~a|If|
-00000230  e9 fe 1e 2c 30 fa 22 03  36 8f 44 27 a7 d2 14 84  |...,0.".6.D'....|
-00000240  d0 1f 21 ca 40 35 d1 7d  31 3f e1 73 de 69 bc da  |..!.@5.}1?.s.i..|
-00000250  a5 96 8a b5 50 2b 4b 87  5a b3 fb e1 11 0a 29 59  |....P+K.Z.....)Y|
-00000260  13 2e e3 c2 05 d3 23 e8  09 0c 42 f6 8e 26 67 89  |......#...B..&g.|
-00000270  24 0f 08 2f 3d 24 2b 0c  a2 98 38 02 5c 95 9f ce  |$../=$+...8.\...|
-00000280  e3 75 ba 05 b5 f8 f0 07  e9 a1 44 16 03 03 00 88  |.u........D.....|
-00000290  0f 00 00 84 04 01 00 80  04 c0 bc 4b 23 59 ed 26  |...........K#Y.&|
-000002a0  8d 90 35 da 5b 55 88 e7  12 10 7b d7 1c 27 d1 c4  |..5.[U....{..'..|
-000002b0  d8 1b e2 e7 54 ad a4 be  00 6b 5b 61 2d ec 97 0c  |....T....k[a-...|
-000002c0  a5 9b ae ab 13 fa 94 53  1c 65 28 21 7d b5 c5 be  |.......S.e(!}...|
-000002d0  22 62 91 78 fc e3 de 84  5c 4e 0d f5 73 5e 20 49  |"b.x....\N..s^ I|
-000002e0  5a e2 f9 d3 2f 36 23 91  31 5b ee c7 0b 6f b3 35  |Z.../6#.1[...o.5|
-000002f0  2f 8a 51 84 3c fe 78 34  1f 8c 68 d3 fc 4f c6 5e  |/.Q.<.x4..h..O.^|
-00000300  7b fe b2 81 79 91 37 ee  7f f1 9b a4 88 5f 1b 44  |{...y.7......_.D|
-00000310  dc e9 36 bb d1 45 bb 1f  14 03 03 00 01 01 16 03  |..6..E..........|
-00000320  03 00 24 12 e7 8a 31 36  26 9f fe 45 95 cf 41 56  |..$...16&..E..AV|
-00000330  b4 69 ef e4 22 14 5a 4d  c8 79 a7 18 7b 68 a8 02  |.i..".ZM.y..{h..|
-00000340  75 ea 42 fe c4 a1 32                              |u.B...2|
+00000200  16 03 03 00 86 10 00 00  82 00 80 79 a7 23 10 fc  |...........y.#..|
+00000210  64 a7 ab 17 ce d6 8b ab  ff c2 44 40 3b ba b4 c6  |d.........D@;...|
+00000220  86 b7 66 7d be 9b fa 66  f9 f6 bb e4 f7 02 16 ea  |..f}...f........|
+00000230  0f 13 9c 8a 98 3a 34 e6  58 82 dc dc 27 3a 3d 5c  |.....:4.X...':=\|
+00000240  99 09 db 48 54 a5 5a a2  16 7f ba 99 d9 0d ca fb  |...HT.Z.........|
+00000250  4a 9e b7 f6 3a ab 26 ef  f9 df a2 0c 4c 45 19 3b  |J...:.&.....LE.;|
+00000260  b2 9f 21 cd ff fc cc c7  fb 91 fa 54 93 a9 42 a9  |..!........T..B.|
+00000270  4c 48 4a 8c 7b 9a d7 90  97 f6 21 89 03 f6 a5 86  |LHJ.{.....!.....|
+00000280  83 6f 21 19 2f 5b f8 ec  a6 36 e9 16 03 03 00 88  |.o!./[...6......|
+00000290  0f 00 00 84 04 01 00 80  0f 9d 15 cc c0 0b 71 8a  |..............q.|
+000002a0  b9 95 ca 9a 86 ff bf 93  8d da 64 ce 99 28 e2 6e  |..........d..(.n|
+000002b0  6d 6f 34 c9 03 fa 87 96  b0 1d 4f b2 3c 9e 4d 2c  |mo4.......O.<.M,|
+000002c0  df be 7d fb 53 fe 90 6f  45 f3 f0 d9 ab 70 d4 df  |..}.S..oE....p..|
+000002d0  5a 95 a4 53 12 02 c1 45  15 c2 2b 69 7e 5f 6f cd  |Z..S...E..+i~_o.|
+000002e0  b3 eb 5d ff 48 36 94 ad  28 29 fe 47 40 ab 9c eb  |..].H6..().G@...|
+000002f0  02 f9 ca 7d e0 48 9f 6e  a4 9f 1e c2 d7 fd 16 18  |...}.H.n........|
+00000300  db ad d9 35 27 89 96 c8  c4 70 10 be a4 5d 6b b4  |...5'....p...]k.|
+00000310  d8 61 70 93 08 00 0f c9  14 03 03 00 01 01 16 03  |.ap.............|
+00000320  03 00 24 7b ee b7 23 12  63 f0 80 ca b3 6f d3 b8  |..${..#.c....o..|
+00000330  ca cc 4a 54 06 ea e5 3e  73 f2 de 1d d6 16 7e 61  |..JT...>s.....~a|
+00000340  32 76 eb f8 8a 66 74                              |2v...ft|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 ae 6d 7b ac b6  |..........$.m{..|
-00000010  62 5c 40 65 6b 0e 5c 12  68 61 14 90 54 3e 24 78  |b\@ek.\.ha..T>$x|
-00000020  be 85 17 a0 9b de a0 00  e9 80 1b a9 0f e4 d7 17  |................|
-00000030  03 03 00 21 86 06 17 6b  62 02 a7 a0 71 fe c0 e4  |...!...kb...q...|
-00000040  44 00 54 dd cc a9 70 cf  bc 92 0d 40 07 62 f5 39  |D.T...p....@.b.9|
-00000050  2a 30 ab 7f cd 15 03 03  00 16 6f 8d c9 d4 62 02  |*0........o...b.|
-00000060  da 64 4c 89 32 86 9f 29  24 05 ed cc 77 9d e5 55  |.dL.2..)$...w..U|
+00000000  14 03 03 00 01 01 16 03  03 00 24 64 d5 a4 78 e9  |..........$d..x.|
+00000010  f1 1d d1 34 f7 b3 95 87  18 f6 cf 65 c6 f0 02 08  |...4.......e....|
+00000020  69 f5 6d aa f2 da fc 2c  ac fc aa f8 25 aa 50 17  |i.m....,....%.P.|
+00000030  03 03 00 21 9f 94 f8 78  46 58 2c 21 0d 30 04 89  |...!...xFX,!.0..|
+00000040  bd 35 03 dc 04 b6 0f 6f  22 65 db 3d 8d 96 00 0c  |.5.....o"e.=....|
+00000050  db bf e5 b3 59 15 03 03  00 16 a6 35 f2 07 5e 32  |....Y......5..^2|
+00000060  4e 09 e4 31 3a f6 4a 83  c2 03 db b9 bf b0 eb 6d  |N..1:.J........m|
index 5de6dd82ec0b27325f879dfcb8c0e4b34056e765..903272b64429673ef3700ae8358ee5f8ba512de7 100644 (file)
@@ -1,10 +1,10 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5a 01 00 00  56 03 03 52 b6 c5 b4 e3  |....Z...V..R....|
-00000010  35 ce 4e b2 9c e0 38 09  e7 fe 00 a2 1a 0a 43 eb  |5.N...8.......C.|
-00000020  df 98 6a 34 71 f9 d0 f8  5d e7 5e 00 00 04 00 05  |..j4q...].^.....|
-00000030  00 ff 01 00 00 29 00 0d  00 20 00 1e 06 01 06 02  |.....)... ......|
-00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000050  03 02 03 03 02 01 02 02  02 03 00 0f 00 01 01     |...............|
+00000000  16 03 01 00 5b 01 00 00  57 03 03 9a 56 e0 d9 b8  |....[...W...V...|
+00000010  ac d5 88 c7 2f d1 87 1b  44 c6 ff 7b 4f 6f f0 2a  |..../...D..{Oo.*|
+00000020  56 a1 9e 46 86 4b 6f 91  29 29 3b 00 00 04 00 05  |V..F.Ko.));.....|
+00000030  00 ff 02 01 00 00 29 00  0d 00 20 00 1e 06 01 06  |......)... .....|
+00000040  02 06 03 05 01 05 02 05  03 04 01 04 02 04 03 03  |................|
+00000050  01 03 02 03 03 02 01 02  02 02 03 00 0f 00 01 01  |................|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002d0  00                                                |.|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 07 0b 00 00  03 00 00 00 16 03 03 00  |................|
-00000010  86 10 00 00 82 00 80 2e  8e cb 6c f5 db 45 5b f0  |..........l..E[.|
-00000020  67 7d b1 ac 87 c2 d6 e9  ea 37 40 15 2a ea a1 af  |g}.......7@.*...|
-00000030  ed 71 68 18 9c 6c 84 20  52 3e 38 94 8e d9 cd b3  |.qh..l. R>8.....|
-00000040  15 73 8b db d7 ff 1d 8a  ed a6 f4 00 7d d0 0a 1e  |.s..........}...|
-00000050  9a 1b 5c 59 f6 a0 29 62  03 a1 c6 bf 8a 57 14 06  |..\Y..)b.....W..|
-00000060  9a e8 03 72 bc cd cd 6f  6d e2 ce a8 41 7a f0 65  |...r...om...Az.e|
-00000070  42 0c 7b dd 93 d7 ab 37  f8 2a b3 c4 72 95 61 e1  |B.{....7.*..r.a.|
-00000080  75 98 f5 99 69 ef 0a d0  00 41 0f 05 87 13 d3 7d  |u...i....A.....}|
-00000090  ba 74 34 43 9a 6c d0 14  03 03 00 01 01 16 03 03  |.t4C.l..........|
-000000a0  00 24 87 7e 7d 48 ca 17  9c ad 30 b8 6a 05 2f d3  |.$.~}H....0.j./.|
-000000b0  fc 18 2e df fd f5 0e 38  c3 06 57 4c 27 66 02 af  |.......8..WL'f..|
-000000c0  6d 78 4d 2e b6 dc                                 |mxM...|
+00000010  86 10 00 00 82 00 80 3a  72 91 a2 c3 ba 83 75 1b  |.......:r.....u.|
+00000020  d3 f6 1c 07 7f 92 a8 b0  1f 47 42 cc 8d 4e 7e 1e  |.........GB..N~.|
+00000030  23 49 44 29 53 19 9f 3b  5c bb 5d ed 6c d9 49 5d  |#ID)S..;\.].l.I]|
+00000040  6e f9 d1 59 9d 40 67 b3  0c ee 41 85 6c 4a 4d 3b  |n..Y.@g...A.lJM;|
+00000050  c1 e6 c8 7f 93 15 cb 2a  17 64 da 70 f3 2a c3 7c  |.......*.d.p.*.||
+00000060  a2 02 48 19 fb 74 5a dc  52 0d 80 6b ed c0 8c 15  |..H..tZ.R..k....|
+00000070  3e 3b 34 7c 55 6e 95 e0  d1 4a 7f b0 bc 33 67 a7  |>;4|Un...J...3g.|
+00000080  3b 40 bb eb 83 58 4a fb  fb 01 9b 0d fa ef 83 c4  |;@...XJ.........|
+00000090  87 10 75 0c a7 ad 91 14  03 03 00 01 01 16 03 03  |..u.............|
+000000a0  00 24 18 ce de 8d ab c1  6e 3b 0b 51 fe 94 ae 0a  |.$......n;.Q....|
+000000b0  39 9c 4d a2 90 53 d4 1e  5f f6 96 5a 51 f2 39 c1  |9.M..S.._..ZQ.9.|
+000000c0  d6 06 c0 4e 58 99                                 |...NX.|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 cf ee f6 28 ea  |..........$...(.|
-00000010  df e2 7e 9a 75 e0 f9 b4  c4 c2 57 3a 54 26 db 7f  |..~.u.....W:T&..|
-00000020  c4 19 6d b6 d6 c7 b1 05  7f 92 21 9e 51 1a 0a 17  |..m.......!.Q...|
-00000030  03 03 00 21 87 48 77 c4  eb 7c 5d 13 3b f4 8d 08  |...!.Hw..|].;...|
-00000040  f9 35 c3 d2 e5 c0 8c ea  15 c9 2d c5 e0 70 fd 7c  |.5........-..p.||
-00000050  de 93 4f 8c 8d 15 03 03  00 16 d4 8a d5 6a fc db  |..O..........j..|
-00000060  c7 1d 1f 76 64 b9 31 68  72 cc 58 de 9f 2a a6 45  |...vd.1hr.X..*.E|
+00000000  14 03 03 00 01 01 16 03  03 00 24 8b 7e 57 f3 7d  |..........$.~W.}|
+00000010  ab 44 f0 c7 53 2d 39 08  14 32 12 4e 4b 45 9a e3  |.D..S-9..2.NKE..|
+00000020  1c 43 36 16 59 a0 4b e4  78 43 d2 a5 dc 96 b1 17  |.C6.Y.K.xC......|
+00000030  03 03 00 21 54 89 75 23  de 7d c7 c6 80 a6 a6 69  |...!T.u#.}.....i|
+00000040  d0 a8 95 77 71 a0 89 34  f4 c3 31 73 bb b0 ac d7  |...wq..4..1s....|
+00000050  e5 e4 83 4b 10 15 03 03  00 16 0d 44 43 67 21 cc  |...K.......DCg!.|
+00000060  6c c1 7e 72 99 aa 7f a1  de 10 0b 36 ae 05 d9 9e  |l.~r.......6....|
index 3b7238ad29970af507f86fe6c2b0d0ce0c63f5bb..8b04a5ad4d973f1040b32c68d1dd9dadc2f9cfab 100644 (file)
@@ -1,15 +1,13 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 a1 01 00 00  9d 03 03 0f b7 07 5f c7  |.............._.|
-00000010  18 b8 39 6d 92 b3 90 ed  bf 5c 48 7c 6a 56 ee e9  |..9m.....\H|jV..|
-00000020  7a 5b 5f 71 a4 f0 7f 47  57 73 78 00 00 04 c0 0a  |z[_q...GWsx.....|
-00000030  00 ff 02 01 00 00 6f 00  0b 00 04 03 00 01 02 00  |......o.........|
-00000040  0a 00 3a 00 38 00 0e 00  0d 00 19 00 1c 00 0b 00  |..:.8...........|
-00000050  0c 00 1b 00 18 00 09 00  0a 00 1a 00 16 00 17 00  |................|
-00000060  08 00 06 00 07 00 14 00  15 00 04 00 05 00 12 00  |................|
-00000070  13 00 01 00 02 00 03 00  0f 00 10 00 11 00 0d 00  |................|
-00000080  20 00 1e 06 01 06 02 06  03 05 01 05 02 05 03 04  | ...............|
-00000090  01 04 02 04 03 03 01 03  02 03 03 02 01 02 02 02  |................|
-000000a0  03 00 0f 00 01 01                                 |......|
+00000000  16 03 01 00 83 01 00 00  7f 03 03 ec 8e d0 43 01  |..............C.|
+00000010  8e 81 3f d8 1f 7e 96 f1  de 4c 94 18 09 1d c5 8c  |..?..~...L......|
+00000020  3a 58 68 5b 3e 7d 46 66  fe 04 74 00 00 04 c0 0a  |:Xh[>}Ff..t.....|
+00000030  00 ff 02 01 00 00 51 00  0b 00 04 03 00 01 02 00  |......Q.........|
+00000040  0a 00 1c 00 1a 00 17 00  19 00 1c 00 1b 00 18 00  |................|
+00000050  1a 00 16 00 0e 00 0d 00  0b 00 0c 00 09 00 0a 00  |................|
+00000060  0d 00 20 00 1e 06 01 06  02 06 03 05 01 05 02 05  |.. .............|
+00000070  03 04 01 04 02 04 03 03  01 03 02 03 03 02 01 02  |................|
+00000080  02 02 03 00 0f 00 01 01                           |........|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 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 05  03 00 8b 30 81 88 02 42  |A.Vk.Z.....0...B|
-000002a0  00 d3 cf 21 cd 3c 2e 11  f5 f8 1d c8 c1 57 4b f8  |...!.<.......WK.|
-000002b0  1a c0 2b 1d 47 0f 2d a5  ac a1 c8 83 5d 76 87 05  |..+.G.-.....]v..|
-000002c0  2b 0d 36 d5 57 9f b9 8a  a0 a2 94 67 6a cd 29 db  |+.6.W......gj.).|
-000002d0  04 b0 6b 06 d9 f7 17 9f  1c 60 92 e7 4e 50 48 7f  |..k......`..NPH.|
-000002e0  dc d0 02 42 01 56 fd 38  bd 05 a5 16 6d 91 d1 ce  |...B.V.8....m...|
-000002f0  bb 8c 45 b2 76 2f 92 9c  8b 94 57 7d de 53 8b 7b  |..E.v/....W}.S.{|
-00000300  80 26 6c 4a 43 4b a6 c9  46 49 08 ab c7 57 f3 d9  |.&lJCK..FI...W..|
-00000310  fa 1d 55 fe 91 de 8a 0d  8b d1 44 96 87 85 cb 02  |..U.......D.....|
-00000320  76 9c 00 ad 5f b8 16 03  03 00 04 0e 00 00 00     |v..._..........|
+000002a0  01 08 89 99 1c 91 97 fb  e8 5b 69 5f f5 36 66 d6  |.........[i_.6f.|
+000002b0  dd 53 04 09 c8 7f c1 25  28 8c 28 57 55 3a 95 3f  |.S.....%(.(WU:.?|
+000002c0  ab 09 47 9a 27 74 83 84  44 cf 86 b7 5e 7f fe db  |..G.'t..D...^...|
+000002d0  05 33 3c 1a b7 f6 bc ff  0d 33 e4 ec 3c e2 1d e2  |.3<......3..<...|
+000002e0  6e ab 02 42 00 92 4e 45  a7 86 e4 bd 40 82 b7 04  |n..B..NE....@...|
+000002f0  12 fe 34 ab e3 c9 4a 05  1f 4e 58 79 67 58 94 53  |..4...J..NXygX.S|
+00000300  e8 1b ba 60 76 92 00 99  a7 5f 0a 98 cb e3 1e de  |...`v...._......|
+00000310  0c df 18 76 58 d5 e1 f1  ef a5 da 9a a3 62 77 50  |...vX........bwP|
+00000320  37 d0 22 d0 31 90 16 03  03 00 04 0e 00 00 00     |7.".1..........|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 0b dc ea 22 05  |....F...BA....".|
-00000010  44 c2 09 47 65 31 3b 0b  e1 05 1a 87 8c 2d 3b 56  |D..Ge1;......-;V|
-00000020  49 34 27 3e d6 3b 93 e2  12 7f 5d 7b dc 85 c8 96  |I4'>.;....]{....|
-00000030  4c 8c f9 18 6f 15 cf db  6e 2c 14 6a c9 dd 1c 70  |L...o...n,.j...p|
-00000040  7e 05 c4 17 71 76 df 10  ee 8c b1 14 03 03 00 01  |~...qv..........|
-00000050  01 16 03 03 00 40 ff 12  88 36 3c 00 17 d1 b9 41  |.....@...6<....A|
-00000060  7a 12 25 94 4c 90 65 62  d8 09 ab f9 b4 ee c3 de  |z.%.L.eb........|
-00000070  46 2f cb ee 18 76 4f 76  8e dd 89 fc 7a 21 3b 5f  |F/...vOv....z!;_|
-00000080  ff ac 1c 03 aa be 96 82  82 ea 2e 22 2a 80 b3 86  |..........."*...|
-00000090  38 e4 4d 90 91 46                                 |8.M..F|
+00000000  16 03 03 00 46 10 00 00  42 41 04 9e 94 25 4f 70  |....F...BA...%Op|
+00000010  a8 e0 87 3a 09 6c 58 4f  5e 76 d9 63 dc c3 d5 63  |...:.lXO^v.c...c|
+00000020  be f2 75 ff 23 23 79 6b  82 fe 56 f5 b9 7a 55 55  |..u.##yk..V..zUU|
+00000030  32 3b ee c5 f0 1f 7b e9  82 01 21 8d 06 03 48 95  |2;....{...!...H.|
+00000040  21 b8 fa 9d 18 2a 08 9c  71 a8 4d 14 03 03 00 01  |!....*..q.M.....|
+00000050  01 16 03 03 00 40 31 f0  7b 5f e8 94 a3 7f b0 12  |.....@1.{_......|
+00000060  a9 80 87 26 eb cf b6 87  61 e7 5b 9b 36 3d 11 bb  |...&....a.[.6=..|
+00000070  21 55 5c f7 e8 f3 b7 1e  f2 06 0d c5 a9 8d f8 48  |!U\............H|
+00000080  c2 2b 8f 83 be 17 4f ec  ff 8e 24 44 74 25 09 40  |.+....O...$Dt%.@|
+00000090  90 fd 70 4d fb bb                                 |..pM..|
 >>> 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 e5 c1 f0 6a db  |..............j.|
-00000020  05 98 ed 33 94 73 7f 13  7f 78 17 7f d1 9e c5 a7  |...3.s...x......|
-00000030  62 7f 85 14 2c 7d b2 8e  ef 75 a9 df 92 cc 22 20  |b...,}...u...." |
-00000040  66 08 85 22 d3 ea 5c 4c  4c c8 d7 17 03 03 00 40  |f.."..\LL......@|
+00000010  00 00 00 00 00 00 00 00  00 00 00 13 eb 4e 56 3d  |.............NV=|
+00000020  1b 10 2e e8 08 65 b9 53  9e 56 49 b7 e9 25 35 94  |.....e.S.VI..%5.|
+00000030  c7 df 7d f7 78 2e f3 8b  9c 2b 9d 42 90 91 5c 97  |..}.x....+.B..\.|
+00000040  22 20 ca 6d a2 83 b3 d8  b3 71 64 17 03 03 00 40  |" .m.....qd....@|
 00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000060  f2 20 07 d2 13 ca ed 01  c9 7b 91 14 01 2c 08 f5  |. .......{...,..|
-00000070  8a 69 94 bc 19 9a d9 65  6b 15 04 b4 45 17 ec 6f  |.i.....ek...E..o|
-00000080  85 de 31 dc a2 de 8b 4d  53 57 66 4a 29 21 5a 20  |..1....MSWfJ)!Z |
+00000060  97 f1 c4 2e bf 6d 85 d5  3d 4b 4a 8b ee 53 08 5a  |.....m..=KJ..S.Z|
+00000070  db 8b 75 49 d9 cb db e3  86 90 ac 93 ce e7 9a 70  |..uI...........p|
+00000080  4c dc 4a f4 c9 f6 b5 fd  f0 3f 9f e9 f9 c3 b3 c6  |L.J......?......|
 00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-000000a0  00 00 00 00 00 55 15 f7  89 8d 75 57 7e 92 db ec  |.....U....uW~...|
-000000b0  32 ec 07 5c 83 32 36 59  61 f1 9d a6 7a eb 76 c1  |2..\.26Ya...z.v.|
-000000c0  c7 96 3f 4d 0a                                    |..?M.|
+000000a0  00 00 00 00 00 5e b1 b7  21 7d 89 65 66 17 d8 79  |.....^..!}.ef..y|
+000000b0  26 db ad 08 28 2c e7 7a  c4 ec 93 19 4f c8 bb 5c  |&...(,.z....O..\|
+000000c0  c2 9e 09 56 07                                    |...V.|
index 20a0731091a6b0b679cacf92de0602b5f92917c9..276050873edd931f5abb53d05e9932919214518d 100644 (file)
@@ -1,11 +1,11 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5e 01 00 00  5a 03 03 f0 0a 06 d0 65  |....^...Z......e|
-00000010  1c c3 90 ac dc 61 42 e5  b8 a9 17 fb e7 c3 1e bd  |.....aB.........|
-00000020  d9 09 5a 63 71 e2 f9 58  db 26 6e 00 00 04 00 05  |..Zcq..X.&n.....|
-00000030  00 ff 01 00 00 2d 00 23  00 00 00 0d 00 20 00 1e  |.....-.#..... ..|
-00000040  06 01 06 02 06 03 05 01  05 02 05 03 04 01 04 02  |................|
-00000050  04 03 03 01 03 02 03 03  02 01 02 02 02 03 00 0f  |................|
-00000060  00 01 01                                          |...|
+00000000  16 03 01 00 5f 01 00 00  5b 03 03 6e cc 37 81 0a  |...._...[..n.7..|
+00000010  b9 fe 58 30 8e 32 61 3c  b1 38 1e 2b f6 ab 44 ee  |..X0.2a<.8.+..D.|
+00000020  f2 cc fe 6e fe 40 65 49  d9 ba aa 00 00 04 00 05  |...n.@eI........|
+00000030  00 ff 02 01 00 00 2d 00  23 00 00 00 0d 00 20 00  |......-.#..... .|
+00000040  1e 06 01 06 02 06 03 05  01 05 02 05 03 04 01 04  |................|
+00000050  02 04 03 03 01 03 02 03  03 02 01 02 02 02 03 00  |................|
+00000060  0f 00 01 01                                       |....|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 35 02 00 00  31 03 03 00 00 00 00 00  |....5...1.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002a0  4f 86 c7 f9 a4 c2 41 34  ac cc f6 ea b0 ab 39 18  |O.....A4......9.|
 000002b0  16 03 03 00 04 0e 00 00  00                       |.........|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 87 06 ba d7 1f  |................|
-00000010  68 0c f2 a6 51 b4 ae af  8c c5 5d d4 bd f1 82 6d  |h...Q.....]....m|
-00000020  1d dd ce 69 be 07 62 13  af 06 71 3a 47 a9 bd f7  |...i..b...q:G...|
-00000030  bb 27 f0 38 df 88 01 40  29 c9 bb 7b 5d 6d 28 bd  |.'.8...@)..{]m(.|
-00000040  c8 28 e6 6d ff 5c c9 d3  c6 f5 06 17 e5 e5 1c 5b  |.(.m.\.........[|
-00000050  a1 18 7a 34 92 0a 39 20  5a 22 44 6c cc 5c 8c 83  |..z4..9 Z"Dl.\..|
-00000060  d0 19 4c bb 4e dc e2 64  ec b2 b8 3f 18 3f 9d 65  |..L.N..d...?.?.e|
-00000070  5b 89 26 ae f6 fd 54 71  c4 45 e9 56 6a 28 42 a9  |[.&...Tq.E.Vj(B.|
-00000080  5b 9f 12 69 a4 08 83 53  95 04 18 14 03 03 00 01  |[..i...S........|
-00000090  01 16 03 03 00 24 55 80  0f 43 c3 08 45 99 c9 1b  |.....$U..C..E...|
-000000a0  fd fe dd e8 48 f2 89 99  86 ef f7 fd 5f 2a 4b 0b  |....H......._*K.|
-000000b0  33 0e 5f 17 bb b7 a2 3c  9d 30                    |3._....<.0|
+00000000  16 03 03 00 86 10 00 00  82 00 80 5d f3 3b c6 24  |...........].;.$|
+00000010  34 17 eb e1 6c de fa cd  ed 6f 42 74 01 5f 4b 22  |4...l....oBt._K"|
+00000020  9e 79 da 68 9f e9 f8 af  84 6b b7 38 52 f3 5e a1  |.y.h.....k.8R.^.|
+00000030  e2 aa d1 48 15 1e 39 6e  18 59 3e dc 57 4a fb b1  |...H..9n.Y>.WJ..|
+00000040  18 18 40 ae 84 da d8 76  50 65 3b a5 d9 7a 72 b1  |..@....vPe;..zr.|
+00000050  51 07 65 08 0e 1d 05 f5  47 a8 7d 79 89 1e fe 00  |Q.e.....G.}y....|
+00000060  89 af 01 7f 4d 0c 11 d7  02 cf 88 7b be 03 c5 65  |....M......{...e|
+00000070  44 77 32 56 5c da 01 53  d1 dd d9 b4 5f 42 85 da  |Dw2V\..S...._B..|
+00000080  82 0b 95 59 45 a3 7a 48  d4 00 22 14 03 03 00 01  |...YE.zH..".....|
+00000090  01 16 03 03 00 24 dd 06  a2 4b a0 8e 8b 31 f2 26  |.....$...K...1.&|
+000000a0  b2 6f d4 5d ff 34 eb 31  42 16 e7 c2 26 3d f7 16  |.o.].4.1B...&=..|
+000000b0  ed bd 41 4b 6f d4 03 fb  b7 83                    |..AKo.....|
 >>> Flow 4 (server to client)
 00000000  16 03 03 00 82 04 00 00  7e 00 00 00 00 00 78 50  |........~.....xP|
 00000010  46 ad c1 db a8 38 86 7b  2b bb fd d0 c3 42 3e 00  |F....8.{+....B>.|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 94  |................|
-00000030  6f 2c b5 83 61 c4 74 90  94 e5 6c fd 70 64 57 3a  |o,..a.t...l.pdW:|
-00000040  25 78 bf 9f a0 7c 51 bc  2a 69 1e b3 fd 71 34 b7  |%x...|Q.*i...q4.|
-00000050  9a ef cb 49 37 f8 5d 5e  7c cf 6d fc 13 c1 52 79  |...I7.]^|.m...Ry|
-00000060  8e ed c3 84 01 33 94 10  65 34 64 5e b4 9c 07 46  |.....3..e4d^...F|
-00000070  5b 9e d7 5e 55 df fd c0  e9 d2 e8 d3 c6 42 18 ef  |[..^U........B..|
-00000080  a5 6c be e8 d2 49 c6 14  03 03 00 01 01 16 03 03  |.l...I..........|
-00000090  00 24 66 94 4b b5 3f 5d  59 db 36 c1 dd 55 8c ee  |.$f.K.?]Y.6..U..|
-000000a0  de a4 bc d0 12 44 31 3e  e4 e7 4a 51 e3 62 69 ab  |.....D1>..JQ.bi.|
-000000b0  14 78 85 49 a3 97 17 03  03 00 21 dd 96 5d 21 e0  |.x.I......!..]!.|
-000000c0  2e 3d 33 dd 6c df bb 41  d7 bd 50 c7 1c 6f 97 34  |.=3.l..A..P..o.4|
-000000d0  6a 6e d6 1d 27 81 2d f7  fb 32 85 02 15 03 03 00  |jn..'.-..2......|
-000000e0  16 5e 4e 62 15 97 a7 a3  9b 1b 50 44 85 fb 28 66  |.^Nb......PD..(f|
-000000f0  aa 66 54 45 c9 dc 61                              |.fTE..a|
+00000030  6f 2c b5 83 61 4d 51 5f  33 46 48 fe 9e e9 83 f4  |o,..aMQ_3FH.....|
+00000040  b1 aa c9 b1 61 2a b2 9d  0f 17 c4 09 f6 26 7a 75  |....a*.......&zu|
+00000050  f1 19 99 db 36 d8 32 f0  94 61 4f 8f ed 80 33 51  |....6.2..aO...3Q|
+00000060  f3 c6 15 84 6b 33 94 c8  4f 84 b7 7c 27 6d 8f fe  |....k3..O..|'m..|
+00000070  41 8e b2 92 ca 80 e8 6c  ba 75 77 f5 3a 87 17 ae  |A......l.uw.:...|
+00000080  f8 b9 6b 10 f9 85 da 14  03 03 00 01 01 16 03 03  |..k.............|
+00000090  00 24 70 bd b9 24 02 ce  69 8a 07 c7 c8 7e cf b7  |.$p..$..i....~..|
+000000a0  4e 2b e2 dc 47 fc f7 3a  c8 2d ab a0 9a ed 27 d9  |N+..G..:.-....'.|
+000000b0  71 ea 45 29 d6 25 17 03  03 00 21 d9 28 ee 99 04  |q.E).%....!.(...|
+000000c0  35 ff ca 3d 30 3f 76 fb  08 1a 56 73 f5 72 c3 fa  |5..=0?v...Vs.r..|
+000000d0  cd 9e 3c 1b 3f 43 4d 56  92 38 9e a6 15 03 03 00  |..<.?CMV.8......|
+000000e0  16 6f 55 57 7b 81 6f 7d  fa 90 76 0b 5b 6d 95 35  |.oUW{.o}..v.[m.5|
+000000f0  39 9f a8 c9 dc b7 80                              |9......|
index a8f7edfa2c011a6cafc4aa631128980832118014..b5eb6c785c20bf4e198175d2ac5f3a7c0fc8351d 100644 (file)
@@ -1,11 +1,11 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5e 01 00 00  5a 03 03 62 f6 20 66 23  |....^...Z..b. f#|
-00000010  d5 71 0a c0 57 92 2e 80  b6 06 0c 54 5b 1c 77 a0  |.q..W......T[.w.|
-00000020  ce 0b b2 52 4a b9 f2 c6  97 33 42 00 00 04 00 05  |...RJ....3B.....|
-00000030  00 ff 01 00 00 2d 00 23  00 00 00 0d 00 20 00 1e  |.....-.#..... ..|
-00000040  06 01 06 02 06 03 05 01  05 02 05 03 04 01 04 02  |................|
-00000050  04 03 03 01 03 02 03 03  02 01 02 02 02 03 00 0f  |................|
-00000060  00 01 01                                          |...|
+00000000  16 03 01 00 5f 01 00 00  5b 03 03 54 25 f9 0f b8  |...._...[..T%...|
+00000010  2d 52 a0 17 b6 62 1c 60  38 31 30 67 f1 55 9c c8  |-R...b.`810g.U..|
+00000020  d3 74 65 bf cd 34 fb 6f  f2 60 7c 00 00 04 00 05  |.te..4.o.`|.....|
+00000030  00 ff 02 01 00 00 2d 00  23 00 00 00 0d 00 20 00  |......-.#..... .|
+00000040  1e 06 01 06 02 06 03 05  01 05 02 05 03 04 01 04  |................|
+00000050  02 04 03 03 01 03 02 03  03 02 01 02 02 02 03 00  |................|
+00000060  0f 00 01 01                                       |....|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 35 02 00 00  31 03 03 00 00 00 00 00  |....5...1.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002a0  4f 86 c7 f9 a4 c2 41 34  ac cc f6 ea b0 ab 39 18  |O.....A4......9.|
 000002b0  16 03 03 00 04 0e 00 00  00                       |.........|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 5b 43 6f db 52  |...........[Co.R|
-00000010  56 e3 d9 4b 1e c8 95 8b  78 a6 19 00 44 9c 44 b4  |V..K....x...D.D.|
-00000020  f7 fe d4 3f 69 ea 9c 67  d3 48 b8 c5 93 bc 22 f1  |...?i..g.H....".|
-00000030  a9 0e 81 82 d0 cf dc 0b  ea f0 02 67 92 8d 72 40  |...........g..r@|
-00000040  25 bb f3 88 53 c0 2f ba  38 ef da d1 7c 73 84 ec  |%...S./.8...|s..|
-00000050  61 96 b9 d4 93 06 4a 06  7b 6d 40 e7 bb 15 59 6e  |a.....J.{m@...Yn|
-00000060  ad 31 71 eb cf 84 57 3b  0c ad aa 70 02 63 24 a9  |.1q...W;...p.c$.|
-00000070  7c a1 9a 6d b7 e0 4c d5  67 4c ce 53 9d b6 31 de  ||..m..L.gL.S..1.|
-00000080  69 b9 f5 ca a8 e3 ea d6  f5 a3 f3 14 03 03 00 01  |i...............|
-00000090  01 16 03 03 00 24 66 ae  13 67 70 20 f5 f5 76 03  |.....$f..gp ..v.|
-000000a0  11 6e 32 a6 73 a2 70 42  ab 4f 16 93 d2 fa a1 ac  |.n2.s.pB.O......|
-000000b0  4e b2 08 4a a9 b5 20 aa  80 b6                    |N..J.. ...|
+00000000  16 03 03 00 86 10 00 00  82 00 80 19 db c8 25 14  |..............%.|
+00000010  e0 7b 6e 87 7b 59 2d 85  8b 47 ce 31 d7 3a 53 06  |.{n.{Y-..G.1.:S.|
+00000020  ff cf 89 ae 45 fd 59 d2  50 c2 31 33 48 81 a8 d7  |....E.Y.P.13H...|
+00000030  47 36 b9 bd 8d f3 f9 f8  c2 6d 6a 8a 6b c4 e5 53  |G6.......mj.k..S|
+00000040  24 52 40 66 49 a9 56 74  4c 94 bc 85 5b 79 5a e1  |$R@fI.VtL...[yZ.|
+00000050  66 3c 42 d8 ca e1 3f c5  36 b8 b5 8c b2 ea 87 68  |f<B...?.6......h|
+00000060  70 eb e3 da 27 fe ed f5  d0 4a c7 fe 46 0b 0f 29  |p...'....J..F..)|
+00000070  19 41 ef dd a9 85 8a 67  02 41 04 30 20 07 09 55  |.A.....g.A.0 ..U|
+00000080  ff 92 44 f1 59 49 39 dd  fa d7 a0 14 03 03 00 01  |..D.YI9.........|
+00000090  01 16 03 03 00 24 82 b5  7b d1 7c 03 93 88 fd 97  |.....$..{.|.....|
+000000a0  54 b7 ff 39 a7 11 c3 cd  53 f3 1c 6c ed ab b6 a0  |T..9....S..l....|
+000000b0  1c b9 89 f0 1a f8 5f 15  7f 85                    |......_...|
 >>> Flow 4 (server to client)
 00000000  16 03 03 00 82 04 00 00  7e 00 00 00 00 00 78 50  |........~.....xP|
 00000010  46 ad c1 db a8 38 86 7b  2b bb fd d0 c3 42 3e 00  |F....8.{+....B>.|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 94  |................|
-00000030  6f 2c b5 83 61 bd 50 da  49 7f 8b 8f 58 57 00 a1  |o,..a.P.I...XW..|
-00000040  11 0d 4a 9d 8a 39 dd 85  23 c0 eb 9d 1a 45 93 92  |..J..9..#....E..|
-00000050  e7 af 15 a3 a4 48 da f9  a4 d8 8e cb 6c 3d 44 77  |.....H......l=Dw|
-00000060  f9 c4 83 89 85 33 94 c1  c6 20 9a 73 44 83 89 5e  |.....3... .sD..^|
-00000070  59 ee 05 c6 7e 8d e9 7d  7b f8 84 46 b6 7d 43 ec  |Y...~..}{..F.}C.|
-00000080  f1 af 1f 0f 35 b4 1c 14  03 03 00 01 01 16 03 03  |....5...........|
-00000090  00 24 8c 0d bd bc 34 93  ed ad 80 21 6d 08 e4 0e  |.$....4....!m...|
-000000a0  67 4f 99 8d df 2a 2d 4f  13 39 82 be a1 d2 1f 75  |gO...*-O.9.....u|
-000000b0  73 c8 b2 ce 41 0c 17 03  03 00 21 d8 c2 50 d6 11  |s...A.....!..P..|
-000000c0  bc 86 58 68 0e 60 4a 47  a5 d0 12 7e a3 b5 be 64  |..Xh.`JG...~...d|
-000000d0  e6 b1 bc 62 70 85 d4 7c  cd fe 67 cf 15 03 03 00  |...bp..|..g.....|
-000000e0  16 e4 1c d5 f4 f7 d0 f5  b2 b3 2b 3d b0 7d c0 23  |..........+=.}.#|
-000000f0  e2 5c a5 c7 a4 23 fa                              |.\...#.|
+00000030  6f 2c b5 83 61 01 55 65  2a 95 38 d4 d5 5f 41 c1  |o,..a.Ue*.8.._A.|
+00000040  45 e4 f8 4b 3b 08 44 df  0b 72 11 93 cd d4 ff 36  |E..K;.D..r.....6|
+00000050  0f 4f 3a a9 4c 9f ab c7  ae 88 97 bc 1e ff 2d 27  |.O:.L.........-'|
+00000060  39 a8 82 84 ae 33 94 48  8b 1c 58 9d 60 65 3c 3f  |9....3.H..X.`e<?|
+00000070  17 9d 6a eb 50 cd 65 04  bb c7 28 c8 0d 57 44 52  |..j.P.e...(..WDR|
+00000080  e0 17 de df f3 13 b1 14  03 03 00 01 01 16 03 03  |................|
+00000090  00 24 5a 41 90 0a eb d9  6b 02 68 3d 98 12 1d fa  |.$ZA....k.h=....|
+000000a0  46 7d 73 ea 8e 49 72 a5  2f 04 40 5c 7d 03 c7 3a  |F}s..Ir./.@\}..:|
+000000b0  6e 50 7c 87 bb 13 17 03  03 00 21 46 da ec ad 52  |nP|.......!F...R|
+000000c0  ea 5a 01 89 15 77 79 af  86 02 b5 89 c8 97 dc f7  |.Z...wy.........|
+000000d0  ac 73 09 87 7a 61 57 d6  9b 17 10 af 15 03 03 00  |.s..zaW.........|
+000000e0  16 bb 20 22 ad 6e 65 66  8c d6 07 e3 82 5f ac 1e  |.. ".nef....._..|
+000000f0  ec 54 72 eb 2d c5 af                              |.Tr.-..|
index 74576264d856b786f17f7ff09a0d86cec6365197..23b6c5be8c2c55fe5959029037eb06b96fb364cb 100644 (file)
@@ -1,10 +1,10 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5a 01 00 00  56 03 03 ac 1d 0b 6e f3  |....Z...V.....n.|
-00000010  25 04 00 97 a0 79 39 c5  ef 95 8b e3 c1 87 0d 1c  |%....y9.........|
-00000020  0b c3 39 3e ff 23 0e 3c  28 8f 75 00 00 04 00 0a  |..9>.#.<(.u.....|
-00000030  00 ff 01 00 00 29 00 0d  00 20 00 1e 06 01 06 02  |.....)... ......|
-00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000050  03 02 03 03 02 01 02 02  02 03 00 0f 00 01 01     |...............|
+00000000  16 03 01 00 5b 01 00 00  57 03 03 1e c8 d0 4c b2  |....[...W.....L.|
+00000010  8d 37 e1 88 c7 0f e0 6a  21 3c 5e 8a bf fa 97 1f  |.7.....j!<^.....|
+00000020  5b 28 bc 6d 47 32 0a 6b  f7 11 f5 00 00 04 00 0a  |[(.mG2.k........|
+00000030  00 ff 02 01 00 00 29 00  0d 00 20 00 1e 06 01 06  |......)... .....|
+00000040  02 06 03 05 01 05 02 05  03 04 01 04 02 04 03 03  |................|
+00000050  01 03 02 03 03 02 01 02  02 02 03 00 0f 00 01 01  |................|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
 000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 15 75 c5 63 e0  |............u.c.|
-00000010  c3 a5 89 dd b3 bf 03 1d  bd 62 86 2e 10 98 79 cb  |.........b....y.|
-00000020  40 3d 9b 36 7e 55 65 d7  80 0a c5 24 ff ad 98 d5  |@=.6~Ue....$....|
-00000030  d4 d9 4e 1b ed 50 0a fa  8a 3e f3 01 c4 e3 47 f7  |..N..P...>....G.|
-00000040  bd 81 fc 33 0b 61 6b b5  3f 38 9b 24 cd 7d 46 66  |...3.ak.?8.$.}Ff|
-00000050  18 87 ea 67 04 b7 ad 23  ac 64 4e 21 cd 29 9f 60  |...g...#.dN!.).`|
-00000060  0e c1 ca 3d 25 d6 d5 2b  e2 60 dc b5 57 be c0 b8  |...=%..+.`..W...|
-00000070  b6 35 25 96 5b 36 55 53  86 b7 90 ef 6c bf 45 2a  |.5%.[6US....l.E*|
-00000080  3d a0 af 08 f0 8a 9c d0  d8 6b 88 14 03 03 00 01  |=........k......|
-00000090  01 16 03 03 00 30 c5 0f  b8 12 c6 5a 42 6a d8 3f  |.....0.....ZBj.?|
-000000a0  f5 49 e4 9a 5d b7 93 90  e7 09 1f 68 40 9d 33 a9  |.I..]......h@.3.|
-000000b0  21 fa 9c 12 c7 7c d4 bf  91 c2 f8 ac 27 b9 8b b6  |!....|......'...|
-000000c0  34 6e f3 c0 fb 83                                 |4n....|
+00000000  16 03 03 00 86 10 00 00  82 00 80 4d c2 e0 9b 40  |...........M...@|
+00000010  44 52 aa 55 06 71 0b bc  17 89 3a 94 d8 d0 1d ed  |DR.U.q....:.....|
+00000020  70 d3 21 30 1b be 97 e0  72 30 60 05 de 9a a9 dd  |p.!0....r0`.....|
+00000030  8c 0c 81 78 3a 15 9c 1c  c6 22 81 0a 10 57 d1 9a  |...x:...."...W..|
+00000040  17 5c 74 9e 58 79 4b f1  70 d9 d9 21 d8 79 64 fa  |.\t.XyK.p..!.yd.|
+00000050  aa a5 e6 93 2a 16 57 23  a7 17 fb 71 b6 c2 d3 5b  |....*.W#...q...[|
+00000060  3d 22 50 16 47 17 5f 15  e8 f1 30 da 10 69 84 25  |="P.G._...0..i.%|
+00000070  05 d0 b5 f0 e8 69 72 4e  93 d3 7c 1a 01 6d 37 fb  |.....irN..|..m7.|
+00000080  cf e1 af f9 da dd 71 56  9b 08 24 14 03 03 00 01  |......qV..$.....|
+00000090  01 16 03 03 00 30 53 ab  b5 09 5a 36 36 df b1 ed  |.....0S...Z66...|
+000000a0  d2 69 5c 45 0b a9 02 8f  6d 25 d4 01 da 5f 27 ab  |.i\E....m%..._'.|
+000000b0  ba 89 6e ee d8 91 24 f8  5e ca 6e 4d 51 41 88 3c  |..n...$.^.nMQA.<|
+000000c0  f8 67 b4 fb d3 cb                                 |.g....|
 >>> Flow 4 (server to client)
 00000000  14 03 03 00 01 01 16 03  03 00 30 00 00 00 00 00  |..........0.....|
-00000010  00 00 00 c1 a2 65 c1 36  63 85 cd ca 5a eb 50 ab  |.....e.6c...Z.P.|
-00000020  bb ec 43 30 37 8f 71 b9  b7 2d 1b bb a2 88 fa d5  |..C07.q..-......|
-00000030  b4 a5 c5 4b 19 71 53 46  7d bb d0 17 03 03 00 30  |...K.qSF}......0|
-00000040  00 00 00 00 00 00 00 00  6a a1 3d c6 35 a0 58 c4  |........j.=.5.X.|
-00000050  ef 12 f2 59 1e 02 42 33  42 5f fe 87 a2 1a ce b7  |...Y..B3B_......|
-00000060  0d d2 36 7c 7f 1a 4c 79  1f 38 34 58 b3 05 fb 96  |..6|..Ly.84X....|
-00000070  15 03 03 00 20 00 00 00  00 00 00 00 00 a1 89 42  |.... ..........B|
-00000080  bc 58 1f 2f 9b c4 d7 e2  d1 ce 1c c9 e0 a5 47 be  |.X./..........G.|
-00000090  63 0c a4 bf 26                                    |c...&|
+00000010  00 00 00 50 83 52 65 2d  6e 76 aa 8d 2d 46 06 12  |...P.Re-nv..-F..|
+00000020  1a e7 25 79 28 61 9e 2d  07 0b fb 3c 77 38 d8 b0  |..%y(a.-...<w8..|
+00000030  af ca 86 8a 51 07 4d 83  39 81 9b 17 03 03 00 30  |....Q.M.9......0|
+00000040  00 00 00 00 00 00 00 00  a1 ea 74 b2 7b fc 3f 9d  |..........t.{.?.|
+00000050  bc eb 9d 09 a2 56 4a ff  d4 fd 00 23 0b e6 69 62  |.....VJ....#..ib|
+00000060  0e 4c 82 43 3f 21 8f b8  fd 5c ce 37 6c 57 d2 98  |.L.C?!...\.7lW..|
+00000070  15 03 03 00 20 00 00 00  00 00 00 00 00 dc 47 cc  |.... .........G.|
+00000080  34 eb 9e 7f d0 8f 5a 32  e6 6d 76 15 18 cc 8d 21  |4.....Z2.mv....!|
+00000090  43 91 81 31 81                                    |C..1.|
index 4ca860d2c262724979c330d23f05088258611fa2..66155e76d30bd2e14d61e6fe15dd35235b528cbe 100644 (file)
@@ -1,10 +1,10 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5a 01 00 00  56 03 03 be 9a 2f 46 66  |....Z...V..../Ff|
-00000010  a3 b3 10 62 63 b6 32 cb  de 1e eb 76 13 50 60 d0  |...bc.2....v.P`.|
-00000020  ee 40 a9 cd 50 ae d8 86  10 37 8b 00 00 04 00 2f  |.@..P....7...../|
-00000030  00 ff 01 00 00 29 00 0d  00 20 00 1e 06 01 06 02  |.....)... ......|
-00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000050  03 02 03 03 02 01 02 02  02 03 00 0f 00 01 01     |...............|
+00000000  16 03 01 00 5b 01 00 00  57 03 03 5a ba 29 44 35  |....[...W..Z.)D5|
+00000010  c4 48 64 61 06 84 70 5c  b5 65 ad 01 9b b2 29 0d  |.Hda..p\.e....).|
+00000020  d1 46 17 3a 27 fb 92 d8  aa 21 aa 00 00 04 00 2f  |.F.:'....!...../|
+00000030  00 ff 02 01 00 00 29 00  0d 00 20 00 1e 06 01 06  |......)... .....|
+00000040  02 06 03 05 01 05 02 05  03 04 01 04 02 04 03 03  |................|
+00000050  01 03 02 03 03 02 01 02  02 02 03 00 0f 00 01 01  |................|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
 000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 61 b4 31 93 2b  |...........a.1.+|
-00000010  d5 e8 06 74 b1 f6 d6 5f  a3 92 78 b6 cf bf 7f ea  |...t..._..x.....|
-00000020  a2 07 1e 90 94 68 5b 19  ae d4 e3 11 78 96 58 fd  |.....h[.....x.X.|
-00000030  96 18 f2 09 58 dc 39 a1  d9 9e 83 f0 24 45 6e 6b  |....X.9.....$Enk|
-00000040  e6 5e e7 cb 94 42 00 10  64 d5 d2 bc 80 23 bd fe  |.^...B..d....#..|
-00000050  5c 3e 3a 80 ff 38 b8 dc  ff 25 ba b0 0a cc ef 94  |\>:..8...%......|
-00000060  a1 31 bd 04 93 91 86 6e  8b fd a1 9d 01 ee 91 a6  |.1.....n........|
-00000070  44 8b 21 55 52 67 3e b1  e4 6e bd 1f 07 85 e1 97  |D.!URg>..n......|
-00000080  7f 55 70 00 5f f4 4b e6  50 45 f7 14 03 03 00 01  |.Up._.K.PE......|
-00000090  01 16 03 03 00 40 71 ff  ab 6d 79 3c da dc 5b 34  |.....@q..my<..[4|
-000000a0  48 39 48 08 e3 29 cb 53  21 fd 67 93 0b f8 81 47  |H9H..).S!.g....G|
-000000b0  40 7f 23 50 5f 94 db 2b  7b 7e 9f 0b bf 38 59 d9  |@.#P_..+{~...8Y.|
-000000c0  6b 57 8f 1e 83 eb 93 2c  62 12 31 c6 f5 21 f2 22  |kW.....,b.1..!."|
-000000d0  7a 82 e9 e6 ec 38                                 |z....8|
+00000000  16 03 03 00 86 10 00 00  82 00 80 ad e8 09 aa 07  |................|
+00000010  c0 3c 8b 39 d2 a8 bd ca  59 eb cf 0a de 33 3e d2  |.<.9....Y....3>.|
+00000020  4f 76 1f 7a 96 50 b3 52  6b 04 9e 6f f1 06 2b 4a  |Ov.z.P.Rk..o..+J|
+00000030  7f 01 f2 51 a3 a7 1e f6  20 a7 27 4e 97 68 61 98  |...Q.... .'N.ha.|
+00000040  9f fd bd aa e8 e6 80 4d  9a 65 51 35 11 44 e4 2c  |.......M.eQ5.D.,|
+00000050  a2 47 33 d1 b6 b7 d5 40  c0 17 34 ff e2 12 8e 00  |.G3....@..4.....|
+00000060  41 e6 4f 3e 56 2f d9 30  6b d9 99 e3 9f ce 10 ba  |A.O>V/.0k.......|
+00000070  7c 95 3b 49 c9 5f 1e 97  37 90 e4 da 9a e0 01 5f  ||.;I._..7......_|
+00000080  b8 6f 95 19 40 0f ca 63  76 6b 2a 14 03 03 00 01  |.o..@..cvk*.....|
+00000090  01 16 03 03 00 40 86 cb  f5 69 1b ee 67 6e 3b be  |.....@...i..gn;.|
+000000a0  e0 de 22 06 8c d4 f4 98  a6 45 1c 2f e5 f0 b4 25  |.."......E./...%|
+000000b0  f4 c0 87 7f e8 1c 2c 1d  20 52 50 fe dc a3 0c 22  |......,. RP...."|
+000000c0  b7 7f d3 9c 42 b8 23 d0  3e fd 93 be a2 50 28 dd  |....B.#.>....P(.|
+000000d0  79 f3 c6 90 c7 bb                                 |y.....|
 >>> 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 45 87 33 41 c1  |...........E.3A.|
-00000020  b8 e7 4c 11 1c 1b 7b 55  51 85 06 01 c1 b6 87 6b  |..L...{UQ......k|
-00000030  01 b3 56 c4 5a 37 ea b6  3a c4 b0 da 1b 5c 15 d4  |..V.Z7..:....\..|
-00000040  03 5a 57 e9 9a 56 16 a5  fa 77 1c 17 03 03 00 40  |.ZW..V...w.....@|
+00000010  00 00 00 00 00 00 00 00  00 00 00 70 e5 19 ef 25  |...........p...%|
+00000020  05 0b 02 79 2b 79 49 e6  2c ad c0 e7 03 b3 40 68  |...y+yI.,.....@h|
+00000030  67 98 31 7c 7e 85 86 a8  5c de 72 3f d1 59 12 20  |g.1|~...\.r?.Y. |
+00000040  87 95 44 57 64 35 03 f5  68 61 20 17 03 03 00 40  |..DWd5..ha ....@|
 00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000060  6f 2e 7c ba 3d 85 4c 7b  1f 13 a5 d6 97 e6 67 f4  |o.|.=.L{......g.|
-00000070  24 d5 a8 d4 26 41 64 0a  fd b3 2e a0 a2 7a 2b 54  |$...&Ad......z+T|
-00000080  a4 1d 6e fe 4c c4 73 e3  76 d0 3a 60 52 df b0 53  |..n.L.s.v.:`R..S|
+00000060  1b 17 7c bb 04 4f 31 7b  da 40 5e 93 64 97 4a 8d  |..|..O1{.@^.d.J.|
+00000070  98 cf 77 2d 01 53 37 53  2c 59 8f ca ac 65 ae f3  |..w-.S7S,Y...e..|
+00000080  f8 d4 ae 67 74 c8 72 21  67 51 9a 1b 71 f2 0e 04  |...gt.r!gQ..q...|
 00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-000000a0  00 00 00 00 00 8b 0a 6d  14 3b 84 bc 7d c6 8d 9d  |.......m.;..}...|
-000000b0  d5 27 32 84 4b 14 75 42  0f aa 5e 88 ba fa a2 c7  |.'2.K.uB..^.....|
-000000c0  16 93 8a c4 fd                                    |.....|
+000000a0  00 00 00 00 00 fd 36 99  3d c7 44 1b 30 39 4a a7  |......6.=.D.09J.|
+000000b0  40 43 e3 01 2b 22 3d c6  8c a1 0d 73 d5 16 d2 25  |@C..+"=....s...%|
+000000c0  19 c8 d7 76 ee                                    |...v.|
index 7a26ebd82a76a932e791f5080e03528826d5595e..a6e7a079a75d00c722e6a62abccc000d5ce2db67 100644 (file)
@@ -1,14 +1,13 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 9a 01 00 00  96 03 03 16 dc f8 f5 3a  |...............:|
-00000010  13 32 e6 1f bd f6 3c 66  b7 4c 67 17 ee b2 2a ba  |.2....<f.Lg...*.|
-00000020  68 5b 8e b1 7c 8f 71 d6  6c 30 e1 00 00 04 c0 2f  |h[..|.q.l0...../|
-00000030  00 ff 01 00 00 69 00 0b  00 04 03 00 01 02 00 0a  |.....i..........|
-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  |................|
-00000060  00 15 00 04 00 05 00 12  00 13 00 01 00 02 00 03  |................|
-00000070  00 0f 00 10 00 11 00 0d  00 20 00 1e 06 01 06 02  |......... ......|
-00000080  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000090  03 02 03 03 02 01 02 02  02 03 00 0f 00 01 01     |...............|
+00000000  16 03 01 00 83 01 00 00  7f 03 03 19 c7 02 a0 bf  |................|
+00000010  5a fb c2 d4 f5 68 0a 19  0f 5e 3a 6b c5 88 17 0b  |Z....h...^:k....|
+00000020  35 ff df ee 06 32 ad 32  99 0e c9 00 00 04 c0 2f  |5....2.2......./|
+00000030  00 ff 02 01 00 00 51 00  0b 00 04 03 00 01 02 00  |......Q.........|
+00000040  0a 00 1c 00 1a 00 17 00  19 00 1c 00 1b 00 18 00  |................|
+00000050  1a 00 16 00 0e 00 0d 00  0b 00 0c 00 09 00 0a 00  |................|
+00000060  0d 00 20 00 1e 06 01 06  02 06 03 05 01 05 02 05  |.. .............|
+00000070  03 04 01 04 02 04 03 03  01 03 02 03 03 02 01 02  |................|
+00000080  02 02 03 00 0f 00 01 01                           |........|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002c0  51 88 35 75 71 b5 e5 54  5b 12 2e 8f 09 67 fd a7  |Q.5uq..T[....g..|
 000002d0  24 20 3e b2 56 1c ce 97  28 5e f8 2b 2d 4f 9e f1  |$ >.V...(^.+-O..|
 000002e0  07 9f 6c 4b 5b 83 56 e2  32 42 e9 58 b6 d7 49 a6  |..lK[.V.2B.X..I.|
-000002f0  b5 68 1a 41 03 56 6b dc  5a 89 05 01 00 80 40 b3  |.h.A.Vk.Z.....@.|
-00000300  66 ee 53 3c 80 f4 da d1  de e6 fe 50 c8 89 60 d5  |f.S<.......P..`.|
-00000310  e4 80 73 39 91 79 6c cf  89 bb a5 da e4 c7 e5 0d  |..s9.yl.........|
-00000320  13 a6 76 24 65 1a a2 b8  cb 95 c2 c6 9d 66 74 57  |..v$e........ftW|
-00000330  9e 90 4f 48 77 88 3a b4  f3 fa 88 ab 61 22 d3 40  |..OHw.:.....a".@|
-00000340  08 c4 0a 69 19 ed c3 ea  d8 15 79 12 d5 ac 8d af  |...i......y.....|
-00000350  41 7d 87 4b a9 ff f8 cb  24 55 88 38 34 11 a5 bd  |A}.K....$U.84...|
-00000360  c1 d6 e5 86 d5 64 b5 f2  df c8 03 f2 a2 6b ff f4  |.....d.......k..|
-00000370  a8 38 e0 18 04 d4 cd bd  e0 cc 63 fc 3f 8b 16 03  |.8........c.?...|
+000002f0  b5 68 1a 41 03 56 6b dc  5a 89 05 01 00 80 97 53  |.h.A.Vk.Z......S|
+00000300  cc 1f a2 55 e2 52 69 a6  b3 78 4f 7e 34 3e 37 e4  |...U.Ri..xO~4>7.|
+00000310  e0 bb 15 ff 96 f8 1d 9c  11 03 2c 68 ca 6d 2b 3c  |..........,h.m+<|
+00000320  b3 96 64 21 d6 3f 81 42  07 c0 1b 85 7e a9 65 54  |..d!.?.B....~.eT|
+00000330  23 89 33 c1 71 b9 29 72  47 8a 0e 71 75 20 d7 b6  |#.3.q.)rG..qu ..|
+00000340  9d c2 ac c1 a8 dc 6c 0e  7e 29 93 fc b2 68 83 2e  |......l.~)...h..|
+00000350  e1 fe e5 eb 54 d7 c3 30  f2 8f 9d 91 49 48 4f 84  |....T..0....IHO.|
+00000360  1a d5 47 75 27 bf c8 09  65 4a a8 7c 65 a0 d0 23  |..Gu'...eJ.|e..#|
+00000370  9f 26 d6 57 62 cb e1 06  64 90 16 73 1b d4 16 03  |.&.Wb...d..s....|
 00000380  03 00 04 0e 00 00 00                              |.......|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 de de ff 8c df  |....F...BA......|
-00000010  d8 4c 72 af 29 3c 4d e0  ed 0f 34 cc fd 2d 52 63  |.Lr.)<M...4..-Rc|
-00000020  94 e8 74 f1 0b 18 69 28  ed 1e f7 62 4e 4f 2c 14  |..t...i(...bNO,.|
-00000030  61 4b 9f 55 d8 70 59 8f  4b a8 ab c6 d2 cd aa 59  |aK.U.pY.K......Y|
-00000040  8a ef 9b b3 f6 ba 52 e5  51 bb a1 14 03 03 00 01  |......R.Q.......|
-00000050  01 16 03 03 00 28 44 1c  eb 89 59 bb ad fb 9f 3f  |.....(D...Y....?|
-00000060  56 06 54 ae 27 6d e4 47  3c 0c 60 30 db 0e d6 0e  |V.T.'m.G<.`0....|
-00000070  9d 0d a9 a0 e7 25 26 6e  99 d0 8f e0 1b 9d        |.....%&n......|
+00000000  16 03 03 00 46 10 00 00  42 41 04 1a 94 a7 1a 36  |....F...BA.....6|
+00000010  d1 ca ad d7 e8 64 03 84  b4 a6 9f dc 30 a2 a3 60  |.....d......0..`|
+00000020  a0 5a 1f a0 3d 8e d1 b8  96 75 37 ee a6 3f d6 ad  |.Z..=....u7..?..|
+00000030  93 b6 7d 58 99 53 04 4b  6e c6 7f 04 bf 60 f9 ba  |..}X.S.Kn....`..|
+00000040  e7 b8 04 73 10 77 ff 22  93 b2 7b 14 03 03 00 01  |...s.w."..{.....|
+00000050  01 16 03 03 00 28 29 6b  2b 14 21 a7 e4 84 c0 9d  |.....()k+.!.....|
+00000060  92 07 cd dd 0b eb c1 b0  76 06 71 48 46 93 b8 05  |........v.qHF...|
+00000070  1a 2b 53 14 da 34 ac 05  4c cc 4d 47 12 28        |.+S..4..L.MG.(|
 >>> 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 92 90 01 f0 70  fa 57 2e 40 d3 4c ef 6a  |.......p.W.@.L.j|
-00000020  03 0c 56 65 f7 c0 3b d0  8a db 48 c9 ae 58 3e 7c  |..Ve..;...H..X>||
-00000030  d1 48 67 17 03 03 00 25  00 00 00 00 00 00 00 01  |.Hg....%........|
-00000040  9e 35 a0 13 73 da 3f 26  ff 1d 90 08 e9 cc 40 7e  |.5..s.?&......@~|
-00000050  82 f3 5e 6e b4 8e 5a 39  7f a4 09 60 b2 15 03 03  |..^n..Z9...`....|
-00000060  00 1a 00 00 00 00 00 00  00 02 04 95 9b 2d 17 1c  |.............-..|
-00000070  6a bc 26 f7 6c 8e f1 c0  0e 82 4a 44              |j.&.l.....JD|
+00000010  00 00 00 b9 c9 6f cb 58  df 1c a1 0a 79 4e fa 8f  |.....o.X....yN..|
+00000020  41 55 8a 0a f8 d1 83 88  28 fb 44 00 8a a5 11 39  |AU......(.D....9|
+00000030  5b d4 83 17 03 03 00 25  00 00 00 00 00 00 00 01  |[......%........|
+00000040  85 4f 2a 54 aa c0 ce 7b  1e 4e e4 64 56 57 68 5e  |.O*T...{.N.dVWh^|
+00000050  fa 41 67 8a da 9d f4 78  a6 c6 13 76 7c 15 03 03  |.Ag....x...v|...|
+00000060  00 1a 00 00 00 00 00 00  00 02 38 71 21 c6 82 bc  |..........8q!...|
+00000070  2e 37 14 1d 15 2f 74 9d  7c 99 d8 66              |.7.../t.|..f|
index d59645c52dbab83daf276ca6a8937e3d725bb814..cc94ac745c14d10e207260cad8fcd2457f451191 100644 (file)
@@ -1,14 +1,13 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 9a 01 00 00  96 03 03 5d 6b 2a ff 74  |...........]k*.t|
-00000010  88 f1 68 8d 1b eb c3 84  34 b5 19 0a 7d f1 9a 0f  |..h.....4...}...|
-00000020  4d c3 0a d7 98 b8 72 e0  73 e4 38 00 00 04 c0 30  |M.....r.s.8....0|
-00000030  00 ff 01 00 00 69 00 0b  00 04 03 00 01 02 00 0a  |.....i..........|
-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  |................|
-00000060  00 15 00 04 00 05 00 12  00 13 00 01 00 02 00 03  |................|
-00000070  00 0f 00 10 00 11 00 0d  00 20 00 1e 06 01 06 02  |......... ......|
-00000080  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000090  03 02 03 03 02 01 02 02  02 03 00 0f 00 01 01     |...............|
+00000000  16 03 01 00 83 01 00 00  7f 03 03 55 9b 71 e2 46  |...........U.q.F|
+00000010  88 58 c4 16 6a 6e 14 3d  3a 5a f9 fe ec 68 71 24  |.X..jn.=:Z...hq$|
+00000020  d0 06 6f a1 56 8f d6 15  42 6b ba 00 00 04 c0 30  |..o.V...Bk.....0|
+00000030  00 ff 02 01 00 00 51 00  0b 00 04 03 00 01 02 00  |......Q.........|
+00000040  0a 00 1c 00 1a 00 17 00  19 00 1c 00 1b 00 18 00  |................|
+00000050  1a 00 16 00 0e 00 0d 00  0b 00 0c 00 09 00 0a 00  |................|
+00000060  0d 00 20 00 1e 06 01 06  02 06 03 05 01 05 02 05  |.. .............|
+00000070  03 04 01 04 02 04 03 03  01 03 02 03 03 02 01 02  |................|
+00000080  02 02 03 00 0f 00 01 01                           |........|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002c0  51 88 35 75 71 b5 e5 54  5b 12 2e 8f 09 67 fd a7  |Q.5uq..T[....g..|
 000002d0  24 20 3e b2 56 1c ce 97  28 5e f8 2b 2d 4f 9e f1  |$ >.V...(^.+-O..|
 000002e0  07 9f 6c 4b 5b 83 56 e2  32 42 e9 58 b6 d7 49 a6  |..lK[.V.2B.X..I.|
-000002f0  b5 68 1a 41 03 56 6b dc  5a 89 05 01 00 80 22 6b  |.h.A.Vk.Z....."k|
-00000300  87 4b f8 ba f2 09 91 ee  ce 81 67 d4 fd d8 b5 07  |.K........g.....|
-00000310  fe c3 88 96 ca e3 3a f0  87 cc ae 44 94 8e 8f 70  |......:....D...p|
-00000320  79 cd de a2 26 4e 17 45  d7 ea 0f 95 a6 c9 7b 17  |y...&N.E......{.|
-00000330  68 7c f5 e8 6c d5 87 6d  5a 7e 53 af 95 0c 42 91  |h|..l..mZ~S...B.|
-00000340  c0 07 18 75 fd 74 1c ad  ef df f8 41 b1 ad fc 36  |...u.t.....A...6|
-00000350  19 31 cf c8 3f 36 55 dd  54 ac 44 a9 3a d1 ae 23  |.1..?6U.T.D.:..#|
-00000360  0a 18 bf b7 6f c7 bc a6  70 50 5e 50 dd da ff 5b  |....o...pP^P...[|
-00000370  67 7d 0a f5 70 a0 8c 88  d9 38 d4 bf a9 c3 16 03  |g}..p....8......|
+000002f0  b5 68 1a 41 03 56 6b dc  5a 89 05 01 00 80 7f 44  |.h.A.Vk.Z......D|
+00000300  af 7b 21 01 6b f0 1c 75  d3 6b 28 99 68 e1 0e d3  |.{!.k..u.k(.h...|
+00000310  a8 cb 5a 2e 23 ad d7 92  73 46 5b 66 88 bd f1 d6  |..Z.#...sF[f....|
+00000320  5d 52 d1 07 53 88 9c 64  e3 ce 80 b3 39 7f 9e 2b  |]R..S..d....9..+|
+00000330  0a 02 a7 e1 3e 00 70 51  3b b4 52 d1 3c 4a e9 f7  |....>.pQ;.R.<J..|
+00000340  0f 85 fa ff d7 ba 96 fc  77 8e 66 8d c6 4c b8 c2  |........w.f..L..|
+00000350  a5 d3 ad 72 f0 8c ba d2  bf 1c 81 7b 4e d5 9e 80  |...r.......{N...|
+00000360  7e b2 90 a0 2f d6 ad c2  33 43 da 46 b0 22 40 ff  |~.../...3C.F."@.|
+00000370  df 95 b3 1e f1 97 b9 7b  61 3c 78 d9 ae cb 16 03  |.......{a<x.....|
 00000380  03 00 04 0e 00 00 00                              |.......|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 d0 f7 11 ae 9f  |....F...BA......|
-00000010  ec 2e ac 8e 97 6c 58 0e  57 32 8e ac fa 3e af 36  |.....lX.W2...>.6|
-00000020  22 e1 41 2b d3 d1 9c c2  1d 51 c0 e4 20 b3 4c 85  |".A+.....Q.. .L.|
-00000030  b8 bd f2 d1 c6 2f 7d 83  c7 43 d9 31 36 1a 83 ca  |...../}..C.16...|
-00000040  c6 89 f8 ba 8c d1 7e 99  04 6e 92 14 03 03 00 01  |......~..n......|
-00000050  01 16 03 03 00 28 32 67  c1 6e 5e 1e 4b 51 1b 70  |.....(2g.n^.KQ.p|
-00000060  54 b9 1d 69 79 38 bd fa  7c 6b 58 71 af 72 08 2d  |T..iy8..|kXq.r.-|
-00000070  55 df 24 be 5b 41 0a ef  0e 90 cf d9 62 81        |U.$.[A......b.|
+00000000  16 03 03 00 46 10 00 00  42 41 04 d8 85 85 d2 78  |....F...BA.....x|
+00000010  27 a5 0a bb 10 67 ec a9  d8 11 f0 ba b9 d7 21 39  |'....g........!9|
+00000020  ed c7 0a a0 a2 69 ab fb  9b 15 e0 d7 ec ca 97 c8  |.....i..........|
+00000030  c0 b2 66 0b 2c 68 37 ac  f0 34 fa 3a 07 dd f2 ae  |..f.,h7..4.:....|
+00000040  8e f6 e3 eb de 08 1f 56  e5 66 eb 14 03 03 00 01  |.......V.f......|
+00000050  01 16 03 03 00 28 f5 2d  89 00 0c 9d d9 0e 54 1b  |.....(.-......T.|
+00000060  71 84 4d c7 bb 98 36 8c  29 b6 06 d8 7b df d9 92  |q.M...6.)...{...|
+00000070  01 00 16 44 5e e3 db f3  8f b7 fa 43 0c f7        |...D^......C..|
 >>> 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 87 2a 3e 09 54  54 c3 58 c0 5b 7b 91 00  |....*>.TT.X.[{..|
-00000020  c4 07 98 9e de 1f f8 04  bb d7 42 04 55 7d 18 a4  |..........B.U}..|
-00000030  41 7c a6 17 03 03 00 25  00 00 00 00 00 00 00 01  |A|.....%........|
-00000040  ab 23 05 51 b4 60 a2 77  01 58 be a6 9f 89 2b b5  |.#.Q.`.w.X....+.|
-00000050  77 6b 19 23 67 f7 89 f1  ef d6 1b f5 e7 15 03 03  |wk.#g...........|
-00000060  00 1a 00 00 00 00 00 00  00 02 8a bf f0 fb 9f 56  |...............V|
-00000070  36 f1 92 49 a9 e5 40 87  f9 87 9e 4d              |6..I..@....M|
+00000010  00 00 00 a4 82 dc d1 67  ed 17 ae 22 13 0d ac d2  |.......g..."....|
+00000020  f4 58 44 5b b4 c6 25 29  80 b6 bc 63 0e 67 22 6e  |.XD[..%)...c.g"n|
+00000030  18 92 48 17 03 03 00 25  00 00 00 00 00 00 00 01  |..H....%........|
+00000040  a0 fe 37 25 fb 4d 29 96  f9 01 67 19 d8 83 26 68  |..7%.M)...g...&h|
+00000050  d0 e8 58 2c ef 90 a3 b5  26 51 26 a9 28 15 03 03  |..X,....&Q&.(...|
+00000060  00 1a 00 00 00 00 00 00  00 02 91 4b d5 54 4a ef  |...........K.TJ.|
+00000070  22 88 ab b7 a2 bb 20 5a  b2 3e 7b 36              |"..... Z.>{6|
index 13163d68f6876ec0e7d6a36c53b684c58c192094..c55f891866d2717e19a7057d80188040d5270565 100644 (file)
@@ -1,10 +1,10 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5a 01 00 00  56 03 03 8a fe f5 09 70  |....Z...V......p|
-00000010  8e 6b e3 2b 12 ff d1 b2  ae 15 bf 47 0e ca 5c b5  |.k.+.......G..\.|
-00000020  bb 0e ad af e5 a6 7e 36  c5 a4 c3 00 00 04 00 05  |......~6........|
-00000030  00 ff 01 00 00 29 00 0d  00 20 00 1e 06 01 06 02  |.....)... ......|
-00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000050  03 02 03 03 02 01 02 02  02 03 00 0f 00 01 01     |...............|
+00000000  16 03 01 00 5b 01 00 00  57 03 03 ec 96 78 51 74  |....[...W....xQt|
+00000010  1b f2 21 ad f2 4f 50 aa  67 f1 20 e2 4f d3 4d 0e  |..!..OP.g. .O.M.|
+00000020  54 91 df 91 d8 81 e3 75  bb 20 c2 00 00 04 00 05  |T......u. ......|
+00000030  00 ff 02 01 00 00 29 00  0d 00 20 00 1e 06 01 06  |......)... .....|
+00000040  02 06 03 05 01 05 02 05  03 04 01 04 02 04 03 03  |................|
+00000050  01 03 02 03 03 02 01 02  02 02 03 00 0f 00 01 01  |................|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
 000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 1c f7 2c 18 38  |.............,.8|
-00000010  d9 41 b5 ab b7 35 2b 75  2d 66 ba c8 70 c2 19 1c  |.A...5+u-f..p...|
-00000020  f2 6d d9 a9 a8 40 8e b5  2c 75 99 06 a5 25 be 0d  |.m...@..,u...%..|
-00000030  b4 b0 9b aa fc 6b 12 a5  b3 e7 02 60 aa 25 e9 7f  |.....k.....`.%..|
-00000040  6b f5 c4 7a 1d 16 a5 d1  76 cc d5 a1 18 68 91 c3  |k..z....v....h..|
-00000050  57 b8 10 f2 b8 81 f3 1b  74 ef 6c 37 3e 81 41 09  |W.......t.l7>.A.|
-00000060  2a c5 15 e6 cc bb 74 4c  01 7a b9 82 5c e2 7f b7  |*.....tL.z..\...|
-00000070  ac 2d 76 30 18 30 c2 19  8c 5f f2 80 41 89 bb 47  |.-v0.0..._..A..G|
-00000080  28 3d 61 cc 3c 06 a8 76  93 57 71 14 03 03 00 01  |(=a.<..v.Wq.....|
-00000090  01 16 03 03 00 24 46 34  1f cc eb 53 c7 d2 04 28  |.....$F4...S...(|
-000000a0  b6 3d 3f 39 06 70 56 b7  db eb 53 9c 66 c3 45 9f  |.=?9.pV...S.f.E.|
-000000b0  69 ca 58 8f e7 ba a7 e6  5a 97                    |i.X.....Z.|
+00000000  16 03 03 00 86 10 00 00  82 00 80 05 4b 04 74 76  |............K.tv|
+00000010  73 3a 92 04 4d 8b 3b 59  c2 43 c5 f4 07 e8 bc a3  |s:..M.;Y.C......|
+00000020  62 44 b7 80 9f 8f bc 43  8a 67 09 64 a7 93 9f f9  |bD.....C.g.d....|
+00000030  2c 55 03 4b e5 87 9d 18  a2 c3 48 4f 02 6e e0 23  |,U.K......HO.n.#|
+00000040  0b 2f 57 81 e4 38 50 11  d6 b1 71 4f c2 e5 a4 03  |./W..8P...qO....|
+00000050  34 a4 eb a1 42 47 79 05  bc 7b b8 26 5b c1 f9 82  |4...BGy..{.&[...|
+00000060  fc 58 49 eb 04 52 fe 57  3c ed 5c 2b d8 fe 49 d7  |.XI..R.W<.\+..I.|
+00000070  d2 2e 6c e8 74 74 0d 87  b3 f6 2d f0 ff 03 f0 2d  |..l.tt....-....-|
+00000080  c8 a2 20 89 3f 3f 11 e1  fb 93 85 14 03 03 00 01  |.. .??..........|
+00000090  01 16 03 03 00 24 9a 81  c0 9e 76 b6 3d 78 37 8e  |.....$....v.=x7.|
+000000a0  ab 33 48 93 bb 0d f4 86  3c ff 72 28 10 35 c2 10  |.3H.....<.r(.5..|
+000000b0  f0 a0 ff 0c 20 f3 c4 29  83 a6                    |.... ..)..|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 78 c3 02 89 60  |..........$x...`|
-00000010  e7 72 9f 51 87 14 ca 2e  0d 79 98 eb 1e 39 62 f9  |.r.Q.....y...9b.|
-00000020  fc a5 c9 2c f8 0c 04 16  60 70 90 b7 31 f8 30 17  |...,....`p..1.0.|
-00000030  03 03 00 21 6a b7 24 73  a7 0d 17 04 d7 54 a8 ea  |...!j.$s.....T..|
-00000040  28 4e f2 0a ef 87 d5 a9  b8 84 81 46 8e 97 d1 ae  |(N.........F....|
-00000050  3c cc b1 6b 72 15 03 03  00 16 1a bb 2f df ae 3e  |<..kr......./..>|
-00000060  a7 89 69 3e 35 f2 f6 cd  35 60 29 3a 6f be 32 0d  |..i>5...5`):o.2.|
+00000000  14 03 03 00 01 01 16 03  03 00 24 93 15 62 c5 2b  |..........$..b.+|
+00000010  4f 8a d7 0f 70 1f 9d 11  fc 8f 9a a9 b7 d7 44 50  |O...p.........DP|
+00000020  6e 0e 5b d7 3b de 15 7d  17 35 31 42 1f a4 40 17  |n.[.;..}.51B..@.|
+00000030  03 03 00 21 a9 ca 73 e9  ce 2d 21 ef 7d bc 40 91  |...!..s..-!.}.@.|
+00000040  41 c9 53 62 af 09 8e b4  37 0f fa ab b7 76 8f 5b  |A.Sb....7....v.[|
+00000050  7d 0f 04 48 49 15 03 03  00 16 76 b1 d7 91 88 6f  |}..HI.....v....o|
+00000060  b4 e7 a4 f1 d2 c2 ac 50  db 31 ae 5c f7 53 a1 68  |.......P.1.\.S.h|
index 8cacd2184087fed16428c58035e8fc5cf1f0d871..521376cedd214f762c7c06aee4618ee074bd4c76 100644 (file)
@@ -1,37 +1,37 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 f6 01 00 00  f2 03 03 53 1e 13 2e bd  |...........S....|
-00000010  ad 66 fd 77 1a ad 5f 4d  cb bd 2e ca b5 c2 45 1d  |.f.w.._M......E.|
-00000020  7c 83 9d 62 3e 39 9c ce  78 99 e7 20 b4 06 b0 ec  ||..b>9..x.. ....|
-00000030  cf b7 52 6e 38 10 31 37  b2 e6 58 0f fa e3 b0 cb  |..Rn8.17..X.....|
-00000040  20 a4 d2 4b f3 7d 92 e6  7e 13 37 08 00 04 00 05  | ..K.}..~.7.....|
-00000050  00 ff 01 00 00 a5 00 23  00 78 50 46 ad c1 db a8  |.......#.xPF....|
-00000060  38 86 7b 2b bb fd d0 c3  42 3e 00 00 00 00 00 00  |8.{+....B>......|
-00000070  00 00 00 00 00 00 00 00  00 00 94 6f 2c b5 83 61  |...........o,..a|
-00000080  c4 74 90 94 e5 6c fd 70  64 57 3a 25 78 bf 9f a0  |.t...l.pdW:%x...|
-00000090  7c 51 bc 2a 69 1e b3 fd  71 34 b7 9a ef cb 49 37  ||Q.*i...q4....I7|
-000000a0  f8 5d 5e 7c cf 6d fc 13  c1 52 79 8e ed c3 84 01  |.]^|.m...Ry.....|
-000000b0  33 94 10 65 34 64 5e b4  9c 07 46 5b 9e d7 5e 55  |3..e4d^...F[..^U|
-000000c0  df fd c0 e9 d2 e8 d3 c6  42 18 ef a5 6c be e8 d2  |........B...l...|
-000000d0  49 c6 00 0d 00 20 00 1e  06 01 06 02 06 03 05 01  |I.... ..........|
-000000e0  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
-000000f0  02 01 02 02 02 03 00 0f  00 01 01                 |...........|
+00000000  16 03 01 00 f7 01 00 00  f3 03 03 35 70 0b ed 1c  |...........5p...|
+00000010  83 57 b1 7b 0a 47 ce d4  07 3a 49 96 93 4c a1 83  |.W.{.G...:I..L..|
+00000020  4b ab b7 ab 7d b0 14 be  dd 91 92 20 09 34 b7 de  |K...}...... .4..|
+00000030  bd 43 e8 cd 8e f3 43 aa  04 64 8f 0a 55 a6 58 ed  |.C....C..d..U.X.|
+00000040  31 8b 3d 4c 84 4f 2c 6d  b0 b1 75 6f 00 04 00 05  |1.=L.O,m..uo....|
+00000050  00 ff 02 01 00 00 a5 00  23 00 78 50 46 ad c1 db  |........#.xPF...|
+00000060  a8 38 86 7b 2b bb fd d0  c3 42 3e 00 00 00 00 00  |.8.{+....B>.....|
+00000070  00 00 00 00 00 00 00 00  00 00 00 94 6f 2c b5 83  |............o,..|
+00000080  61 4d 51 5f 33 46 48 fe  9e e9 83 f4 b1 aa c9 b1  |aMQ_3FH.........|
+00000090  61 2a b2 9d 0f 17 c4 09  f6 26 7a 75 f1 19 99 db  |a*.......&zu....|
+000000a0  36 d8 32 f0 94 61 4f 8f  ed 80 33 51 f3 c6 15 84  |6.2..aO...3Q....|
+000000b0  6b 33 94 c8 4f 84 b7 7c  27 6d 8f fe 41 8e b2 92  |k3..O..|'m..A...|
+000000c0  ca 80 e8 6c ba 75 77 f5  3a 87 17 ae f8 b9 6b 10  |...l.uw.:.....k.|
+000000d0  f9 85 da 00 0d 00 20 00  1e 06 01 06 02 06 03 05  |...... .........|
+000000e0  01 05 02 05 03 04 01 04  02 04 03 03 01 03 02 03  |................|
+000000f0  03 02 01 02 02 02 03 00  0f 00 01 01              |............|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 51 02 00 00  4d 03 03 00 00 00 00 00  |....Q...M.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 20 b4 06 b0 ec  |........... ....|
-00000030  cf b7 52 6e 38 10 31 37  b2 e6 58 0f fa e3 b0 cb  |..Rn8.17..X.....|
-00000040  20 a4 d2 4b f3 7d 92 e6  7e 13 37 08 00 05 00 00  | ..K.}..~.7.....|
+00000020  00 00 00 00 00 00 00 00  00 00 00 20 09 34 b7 de  |........... .4..|
+00000030  bd 43 e8 cd 8e f3 43 aa  04 64 8f 0a 55 a6 58 ed  |.C....C..d..U.X.|
+00000040  31 8b 3d 4c 84 4f 2c 6d  b0 b1 75 6f 00 05 00 00  |1.=L.O,m..uo....|
 00000050  05 ff 01 00 01 00 14 03  03 00 01 01 16 03 03 00  |................|
-00000060  24 24 31 13 8c 45 4f 8a  fc 71 50 94 b0 6f 02 5e  |$$1..EO..qP..o.^|
-00000070  da d3 a3 13 8b c8 53 fb  54 8d ef 90 f7 55 b1 be  |......S.T....U..|
-00000080  37 30 05 e5 5d                                    |70..]|
+00000060  24 18 67 37 5a c6 ea 3f  5f 06 2d c3 f1 2a ff d3  |$.g7Z..?_.-..*..|
+00000070  45 ce fe 38 1a e6 39 25  e7 e5 01 4d 6e fd 23 af  |E..8..9%...Mn.#.|
+00000080  dc 67 1b 1d e2                                    |.g...|
 >>> Flow 3 (client to server)
-00000000  14 03 03 00 01 01 16 03  03 00 24 ed dd e4 a5 09  |..........$.....|
-00000010  0d 7c cb e4 90 9c a1 1c  21 f4 13 bd 45 8f f4 d8  |.|......!...E...|
-00000020  7e e2 89 7a 0d f4 75 99  66 8c 05 a3 1a e2 2b     |~..z..u.f.....+|
+00000000  14 03 03 00 01 01 16 03  03 00 24 b5 75 e6 1d 1d  |..........$.u...|
+00000010  cb 2c 5d 9f d1 07 de 23  11 84 c2 59 50 55 72 27  |.,]....#...YPUr'|
+00000020  f2 5e 34 e2 c1 53 bf 21  5f f4 c4 2c f1 e1 7a     |.^4..S.!_..,..z|
 >>> Flow 4 (server to client)
-00000000  17 03 03 00 21 69 fa 9e  98 fb 7a 95 b1 8e e5 74  |....!i....z....t|
-00000010  03 02 d7 3d 69 c4 b8 c9  5b 49 e3 30 32 e3 c5 6a  |...=i...[I.02..j|
-00000020  fa 20 98 bd 01 ed 15 03  03 00 16 c9 b1 20 1f 30  |. ........... .0|
-00000030  c1 2f 15 75 cd 82 45 de  1a 81 cd dc 10 05 1c 45  |./.u..E........E|
-00000040  dc                                                |.|
+00000000  17 03 03 00 21 93 92 dd  07 a3 8f 3d 34 6d b8 94  |....!......=4m..|
+00000010  a7 6f 18 27 e7 cd 30 0a  08 4f b6 9b cb 43 93 27  |.o.'..0..O...C.'|
+00000020  b6 8b 83 ae d6 8a 15 03  03 00 16 68 a1 a4 f8 66  |...........h...f|
+00000030  8a c0 e7 d3 97 83 cb 35  94 84 7a e6 47 3c 97 8c  |.......5..z.G<..|
+00000040  69                                                |i|
index 912c1787a1e1c96cb8e898ef6a928501f378645a..c3cd2efeb946f12abe9d0f1b1e7db3dcf06ed876 100644 (file)
@@ -1,20 +1,20 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 f6 01 00 00  f2 03 03 aa 0c c2 75 42  |..............uB|
-00000010  62 2a 1d 14 a0 cc a1 e4  a7 19 77 50 80 2b f8 05  |b*........wP.+..|
-00000020  0b fa 60 3a a7 a7 84 d3  e1 68 26 20 68 97 0c ae  |..`:.....h& h...|
-00000030  7b 1d bc 13 14 a8 f6 c1  e1 96 1f 54 18 2c cb 99  |{..........T.,..|
-00000040  17 7d be 45 6a 39 53 c6  50 c7 8c 75 00 04 00 05  |.}.Ej9S.P..u....|
-00000050  00 ff 01 00 00 a5 00 23  00 78 50 46 ad c1 db a8  |.......#.xPF....|
-00000060  38 86 7b 2b bb fd d0 c3  42 3e 00 00 00 00 00 00  |8.{+....B>......|
-00000070  00 00 00 00 00 00 00 00  00 00 94 6f 2c b5 83 61  |...........o,..a|
-00000080  bd 50 da 49 7f 8b 8f 58  57 00 a1 11 0d 4a 9d 8a  |.P.I...XW....J..|
-00000090  39 dd 85 23 c0 eb 9d 1a  45 93 92 e7 af 15 a3 a4  |9..#....E.......|
-000000a0  48 da f9 a4 d8 8e cb 6c  3d 44 77 f9 c4 83 89 85  |H......l=Dw.....|
-000000b0  33 94 c1 c6 20 9a 73 44  83 89 5e 59 ee 05 c6 7e  |3... .sD..^Y...~|
-000000c0  8d e9 7d 7b f8 84 46 b6  7d 43 ec f1 af 1f 0f 35  |..}{..F.}C.....5|
-000000d0  b4 1c 00 0d 00 20 00 1e  06 01 06 02 06 03 05 01  |..... ..........|
-000000e0  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
-000000f0  02 01 02 02 02 03 00 0f  00 01 01                 |...........|
+00000000  16 03 01 00 f7 01 00 00  f3 03 03 2b 89 3f 02 47  |...........+.?.G|
+00000010  f6 14 64 3b 64 08 84 6e  9c e1 c9 4d 4f 30 92 06  |..d;d..n...MO0..|
+00000020  d1 19 58 5d 93 30 41 4d  a6 2c f6 20 53 3c e7 f4  |..X].0AM.,. S<..|
+00000030  23 7e 59 b1 32 c4 2d db  0b 6f ab 64 4a 72 c9 31  |#~Y.2.-..o.dJr.1|
+00000040  d9 b9 38 a8 b4 4e 0c 39  f8 f4 61 7a 00 04 00 05  |..8..N.9..az....|
+00000050  00 ff 02 01 00 00 a5 00  23 00 78 50 46 ad c1 db  |........#.xPF...|
+00000060  a8 38 86 7b 2b bb fd d0  c3 42 3e 00 00 00 00 00  |.8.{+....B>.....|
+00000070  00 00 00 00 00 00 00 00  00 00 00 94 6f 2c b5 83  |............o,..|
+00000080  61 01 55 65 2a 95 38 d4  d5 5f 41 c1 45 e4 f8 4b  |a.Ue*.8.._A.E..K|
+00000090  3b 08 44 df 0b 72 11 93  cd d4 ff 36 0f 4f 3a a9  |;.D..r.....6.O:.|
+000000a0  4c 9f ab c7 ae 88 97 bc  1e ff 2d 27 39 a8 82 84  |L.........-'9...|
+000000b0  ae 33 94 48 8b 1c 58 9d  60 65 3c 3f 17 9d 6a eb  |.3.H..X.`e<?..j.|
+000000c0  50 cd 65 04 bb c7 28 c8  0d 57 44 52 e0 17 de df  |P.e...(..WDR....|
+000000d0  f3 13 b1 00 0d 00 20 00  1e 06 01 06 02 06 03 05  |...... .........|
+000000e0  01 05 02 05 03 04 01 04  02 04 03 03 01 03 02 03  |................|
+000000f0  03 02 01 02 02 02 03 00  0f 00 01 01              |............|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
 000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 ac 10 32 61 b0  |.............2a.|
-00000010  03 e3 1e 2f 89 91 5f d6  4c e0 82 a7 82 41 67 d3  |.../.._.L....Ag.|
-00000020  5f b3 68 2d c0 d1 6f 03  7b 79 94 cc bb 35 6c 8a  |_.h-..o.{y...5l.|
-00000030  bf 1c 83 ff 88 91 5c 04  64 cc a0 df 0b 08 8c 0f  |......\.d.......|
-00000040  72 13 17 9f 27 14 8d 9a  af 17 70 41 44 9f 89 8c  |r...'.....pAD...|
-00000050  fa e4 66 33 4d bd 2f 93  2a 1e 85 a1 af 9e 27 12  |..f3M./.*.....'.|
-00000060  59 a4 13 67 56 85 c2 86  47 f8 c5 49 8f a4 c2 6e  |Y..gV...G..I...n|
-00000070  04 78 0f 11 2b fb 7e 34  b8 eb 25 93 71 ab 9f f5  |.x..+.~4..%.q...|
-00000080  93 df 2b c3 1e 9e 6a 9e  e3 57 aa 14 03 03 00 01  |..+...j..W......|
-00000090  01 16 03 03 00 24 e0 13  15 10 4c db f3 b6 de d2  |.....$....L.....|
-000000a0  68 02 f5 ea 1f 8e 58 70  4a 5a 78 d9 66 c5 74 77  |h.....XpJZx.f.tw|
-000000b0  a0 3a ec d8 b7 42 e3 a5  d4 62                    |.:...B...b|
+00000000  16 03 03 00 86 10 00 00  82 00 80 ab d9 61 5e d3  |.............a^.|
+00000010  87 d7 eb 21 12 6f f9 61  dd 8b de 76 d7 14 70 2f  |...!.o.a...v..p/|
+00000020  9c 0f 3c d4 4c 77 41 e2  ac 73 18 c3 0f 66 f2 b1  |..<.LwA..s...f..|
+00000030  fd 4b 1e d9 cb 5c 94 16  4d c2 98 f9 0d 55 f7 79  |.K...\..M....U.y|
+00000040  e2 8d 2c 87 96 e7 10 fb  78 fb ce 27 5d 9f ac 97  |..,.....x..']...|
+00000050  d6 54 6f 0c 78 dc 7b 2e  49 4c e2 42 24 b9 3d de  |.To.x.{.IL.B$.=.|
+00000060  89 5f 1a 40 54 33 11 96  89 6f 59 25 5e 89 60 40  |._.@T3...oY%^.`@|
+00000070  83 8c 0e 92 0e 7d 68 9d  17 74 ba 39 e8 6f e3 43  |.....}h..t.9.o.C|
+00000080  44 80 e6 62 4b 35 43 21  5b eb 32 14 03 03 00 01  |D..bK5C![.2.....|
+00000090  01 16 03 03 00 24 77 1a  b5 2c 88 d7 a6 83 f5 30  |.....$w..,.....0|
+000000a0  a0 c3 b4 45 a6 af 9b c2  ac 55 cf 73 4f a0 ba e5  |...E.....U.sO...|
+000000b0  2a be 9c 97 d2 d2 0b e9  95 0e                    |*.........|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 e9 c1 1f 5b e6  |..........$...[.|
-00000010  c1 d5 8a 14 eb c6 41 c1  77 6d 59 83 b6 95 34 f9  |......A.wmY...4.|
-00000020  7b a1 c9 9d 58 a5 b2 1b  33 6e 04 ab e0 03 61 17  |{...X...3n....a.|
-00000030  03 03 00 21 67 8b 55 43  d7 a7 05 c9 1f a0 d3 65  |...!g.UC.......e|
-00000040  30 36 07 8f d8 52 7e 40  79 31 2e 1c 1a c2 a6 fe  |06...R~@y1......|
-00000050  e0 39 4d a0 5d 15 03 03  00 16 b8 94 fb 17 e5 1d  |.9M.]...........|
-00000060  2e 28 95 cf 02 85 8e 11  2e 16 b1 53 72 aa a4 94  |.(.........Sr...|
+00000000  14 03 03 00 01 01 16 03  03 00 24 a9 ae 0c a5 ed  |..........$.....|
+00000010  51 10 d9 14 71 41 40 bd  be f5 44 98 11 2f d8 0f  |Q...qA@...D../..|
+00000020  4d 42 bf 28 53 bf 02 7e  d6 16 92 7f dd 03 ec 17  |MB.(S..~........|
+00000030  03 03 00 21 46 c2 68 a1  6a 35 67 e7 7d 62 71 43  |...!F.h.j5g.}bqC|
+00000040  6b ea d6 fc 22 fc 2d ad  45 d6 6d 98 9e e5 88 a0  |k...".-.E.m.....|
+00000050  ac 80 f7 6f 05 15 03 03  00 16 0c ae f4 fc 0e 09  |...o............|
+00000060  0b 09 73 69 83 0d 00 89  39 ff f6 20 4e 2b 88 3d  |..si....9.. N+.=|
index aee57421a23447cf85db50dfd831001e06028f68..ae52ac2ae182130cdaa7de9bbda44dff439cbe42 100644 (file)
@@ -1,12 +1,12 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 6e 01 00 00  6a 03 03 be 99 22 5c d2  |....n...j...."\.|
-00000010  02 c7 a6 be f3 33 7a d4  76 1f cf 1e 39 0b 25 7c  |.....3z.v...9.%||
-00000020  32 70 e4 8c 49 a6 87 b9  c1 2f 6d 00 00 04 00 2f  |2p..I..../m..../|
-00000030  00 ff 01 00 00 3d 00 00  00 10 00 0e 00 00 0b 73  |.....=.........s|
-00000040  6e 69 74 65 73 74 2e 63  6f 6d 00 0d 00 20 00 1e  |nitest.com... ..|
-00000050  06 01 06 02 06 03 05 01  05 02 05 03 04 01 04 02  |................|
-00000060  04 03 03 01 03 02 03 03  02 01 02 02 02 03 00 0f  |................|
-00000070  00 01 01                                          |...|
+00000000  16 03 01 00 6f 01 00 00  6b 03 03 07 0f b6 b9 cc  |....o...k.......|
+00000010  db 23 57 92 d0 9b 37 72  9d ad 9a 0d 17 6b dd b8  |.#W...7r.....k..|
+00000020  81 b7 7c 54 dd 68 fe 4e  28 00 39 00 00 04 00 2f  |..|T.h.N(.9..../|
+00000030  00 ff 02 01 00 00 3d 00  00 00 10 00 0e 00 00 0b  |......=.........|
+00000040  73 6e 69 74 65 73 74 2e  63 6f 6d 00 0d 00 20 00  |snitest.com... .|
+00000050  1e 06 01 06 02 06 03 05  01 05 02 05 03 04 01 04  |................|
+00000060  02 04 03 03 01 03 02 03  03 02 01 02 02 02 03 00  |................|
+00000070  0f 00 01 01                                       |....|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000230  2c 65 25 d6 52 b6 e3 18  45 bd cc 16 03 03 00 04  |,e%.R...E.......|
 00000240  0e 00 00 00                                       |....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 6b 03 31 ca a0  |...........k.1..|
-00000010  62 a2 53 11 ce 13 d9 f6  e7 d4 ec 2e c3 0a 38 56  |b.S...........8V|
-00000020  23 22 67 23 c8 8d 16 b4  3c 0b 26 9f 1c 2d 65 13  |#"g#....<.&..-e.|
-00000030  c3 cb 65 69 b0 47 ff 87  e8 02 56 c4 77 8a 40 29  |..ei.G....V.w.@)|
-00000040  82 62 8b 06 61 0a 1c b3  c7 29 b6 aa c9 96 37 18  |.b..a....)....7.|
-00000050  d0 60 66 63 9b 62 4b 30  cc 03 9c 37 05 c6 32 98  |.`fc.bK0...7..2.|
-00000060  cb a0 e2 e4 38 60 d4 93  99 9a fc 03 66 fb b6 ef  |....8`......f...|
-00000070  8a 1e bb ca 13 c5 d9 7a  7c 3b 50 dc d0 ad 00 b5  |.......z|;P.....|
-00000080  2c dc 1a ef c4 5c af d3  4e cd e6 14 03 03 00 01  |,....\..N.......|
-00000090  01 16 03 03 00 40 42 31  83 8a 2c 86 22 c5 df e5  |.....@B1..,."...|
-000000a0  f2 0b f8 0c 2f 1e 82 f4  69 fe 1d bd 4c db f1 80  |..../...i...L...|
-000000b0  68 30 b7 e3 60 76 b3 f1  52 ae d6 e7 b3 cb 4a e0  |h0..`v..R.....J.|
-000000c0  27 0a c1 1a 72 ed 71 ab  0a fc 10 d9 5e 4d fd 10  |'...r.q.....^M..|
-000000d0  04 92 39 78 be 23                                 |..9x.#|
+00000000  16 03 03 00 86 10 00 00  82 00 80 72 6a 6f a8 c9  |...........rjo..|
+00000010  3e 4c 33 da 92 23 97 68  fc 4e ca 74 77 98 f3 88  |>L3..#.h.N.tw...|
+00000020  ba a0 55 b6 a0 6f ff c8  db 2b 90 17 1f 45 bc 26  |..U..o...+...E.&|
+00000030  62 6e b9 91 96 b9 03 5d  eb f2 a2 59 87 7b 81 4a  |bn.....]...Y.{.J|
+00000040  0c f9 e2 23 60 e3 c7 4d  53 4f 3a 1f c5 5f dd 15  |...#`..MSO:.._..|
+00000050  cc 78 c5 21 fd 33 02 68  77 7c 8d 5f e8 80 a7 84  |.x.!.3.hw|._....|
+00000060  a7 2c b3 1f 64 df 8a 63  e9 b3 24 02 c1 6a 94 bd  |.,..d..c..$..j..|
+00000070  a1 62 e5 32 e5 d9 83 25  0d 0f 1a 02 90 8a cd 79  |.b.2...%.......y|
+00000080  1c bd 4a c2 f4 5d a0 24  c6 c1 ae 14 03 03 00 01  |..J..].$........|
+00000090  01 16 03 03 00 40 1f 1a  17 47 15 25 5b 3d 5f e5  |.....@...G.%[=_.|
+000000a0  f4 d9 64 47 5f 80 09 f7  dd 5a ff 58 19 08 b5 db  |..dG_....Z.X....|
+000000b0  38 88 a4 44 07 01 fb 80  1d 89 b2 d4 af 95 80 b3  |8..D............|
+000000c0  75 13 82 0e 24 12 1d 5c  29 72 1d 21 d4 69 16 e0  |u...$..\)r.!.i..|
+000000d0  b5 4b 46 62 fe f7                                 |.KFb..|
 >>> Flow 4 (server to client)
 00000000  15 03 03 00 02 02 14                              |.......|
index 40d3714a86db625f08b51f63c4f9116674f67c7e..7ac8dc92a77c663b9f8e4ae1e68e16972b651e9d 100644 (file)
@@ -1,12 +1,12 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 6e 01 00 00  6a 03 03 23 de 75 da 8e  |....n...j..#.u..|
-00000010  0a 4b 7b e4 cb 34 14 83  be d1 6a 95 25 86 f8 91  |.K{..4....j.%...|
-00000020  d8 bb ac 82 9e 19 d6 9f  52 26 f6 00 00 04 00 2f  |........R&...../|
-00000030  00 ff 01 00 00 3d 00 00  00 10 00 0e 00 00 0b 73  |.....=.........s|
-00000040  6e 69 74 65 73 74 2e 63  6f 6d 00 0d 00 20 00 1e  |nitest.com... ..|
-00000050  06 01 06 02 06 03 05 01  05 02 05 03 04 01 04 02  |................|
-00000060  04 03 03 01 03 02 03 03  02 01 02 02 02 03 00 0f  |................|
-00000070  00 01 01                                          |...|
+00000000  16 03 01 00 6f 01 00 00  6b 03 03 fe d6 ce b5 1b  |....o...k.......|
+00000010  1c 50 0c db 9c 35 5d 0e  f2 ee 57 3f 65 83 9f 28  |.P...5]...W?e..(|
+00000020  96 50 1c e0 7f 95 f9 17  39 4f c3 00 00 04 00 2f  |.P......9O...../|
+00000030  00 ff 02 01 00 00 3d 00  00 00 10 00 0e 00 00 0b  |......=.........|
+00000040  73 6e 69 74 65 73 74 2e  63 6f 6d 00 0d 00 20 00  |snitest.com... .|
+00000050  1e 06 01 06 02 06 03 05  01 05 02 05 03 04 01 04  |................|
+00000060  02 04 03 03 01 03 02 03  03 02 01 02 02 02 03 00  |................|
+00000070  0f 00 01 01                                       |....|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000230  2c 65 25 d6 52 b6 e3 18  45 bd cc 16 03 03 00 04  |,e%.R...E.......|
 00000240  0e 00 00 00                                       |....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 a2 99 61 c5 90  |.............a..|
-00000010  47 1a e7 47 56 51 59 e4  6e ab 82 01 18 78 ee 95  |G..GVQY.n....x..|
-00000020  b8 e2 c7 c7 f9 64 98 dd  84 8d 96 d9 2d 08 62 1e  |.....d......-.b.|
-00000030  4f 29 83 b6 93 68 77 7a  14 1b f0 b3 1a 67 7b 7a  |O)...hwz.....g{z|
-00000040  f9 54 f3 7e 6d eb b6 7a  c9 37 70 6a 83 68 f2 15  |.T.~m..z.7pj.h..|
-00000050  81 07 30 6e b8 fa 19 0e  46 dc d6 9a 4a 8e 8d f1  |..0n....F...J...|
-00000060  05 78 60 75 d4 00 d9 1e  11 5f 16 f7 bc 9f e8 8a  |.x`u....._......|
-00000070  c4 3e bd d9 1a b8 67 50  00 be 5f 43 ee 07 ad be  |.>....gP.._C....|
-00000080  f5 85 67 fc 8f c6 87 47  6d 6e b2 14 03 03 00 01  |..g....Gmn......|
-00000090  01 16 03 03 00 40 91 7d  7b 05 99 48 05 70 a9 67  |.....@.}{..H.p.g|
-000000a0  e9 7a 0a c3 6b bf b0 ad  68 65 17 fb 18 bf 8d bd  |.z..k...he......|
-000000b0  e1 4b 12 bf ea 82 9d a6  1e 3a c8 77 65 32 bd 5e  |.K.......:.we2.^|
-000000c0  c4 46 da e7 e1 ac 09 fe  4a ac bc 57 6a 17 7d dc  |.F......J..Wj.}.|
-000000d0  fe 9c d0 d0 6e fc                                 |....n.|
+00000000  16 03 03 00 86 10 00 00  82 00 80 6f bc 33 c8 2d  |...........o.3.-|
+00000010  5a 50 65 2f 06 1a 45 16  9e 5b ab 97 43 b1 9e 96  |ZPe/..E..[..C...|
+00000020  b5 4a fe c3 7c e8 e4 07  ea 00 47 d2 51 23 11 ae  |.J..|.....G.Q#..|
+00000030  11 a8 79 71 b9 c6 82 17  40 ae c7 fc cd 05 4d 6d  |..yq....@.....Mm|
+00000040  cb bc f1 ce 30 d0 10 37  4a e6 aa d3 14 fb bc 62  |....0..7J......b|
+00000050  eb 6c fa ec e1 e1 dd 63  39 95 0b 87 71 a0 83 ba  |.l.....c9...q...|
+00000060  bf 25 f8 a9 d3 c4 35 e1  88 23 85 56 c6 f4 0b 10  |.%....5..#.V....|
+00000070  d1 70 f8 0a 3d a1 08 17  ce 27 2d 4c a7 c5 b5 0d  |.p..=....'-L....|
+00000080  f2 43 b7 b9 02 21 7a eb  40 d2 66 14 03 03 00 01  |.C...!z.@.f.....|
+00000090  01 16 03 03 00 40 0a 93  47 0b 6e 40 ff cd 09 a5  |.....@..G.n@....|
+000000a0  bc a4 c5 a8 c3 1c 0a fb  d4 2e 8a 2f 0c f3 d6 e1  |.........../....|
+000000b0  de 1f 56 2f 09 61 2d 31  d5 b1 29 6b f2 18 8b f2  |..V/.a-1..)k....|
+000000c0  0c 0e 09 5f ec 11 56 af  44 8b e5 2d 09 68 eb c2  |..._..V.D..-.h..|
+000000d0  91 4d 04 b2 10 02                                 |.M....|
 >>> Flow 4 (server to client)
 00000000  15 03 03 00 02 02 14                              |.......|
index 904f69ecacb5f43ce5c61e29a26b8c5a161c64e4..32c0d4a5456bc093d578d025a8091b643b141b80 100644 (file)
@@ -1,12 +1,12 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 6e 01 00 00  6a 03 03 27 db e3 e8 f4  |....n...j..'....|
-00000010  48 1d 45 d5 20 64 97 b2  20 a6 67 94 7a 1e 87 12  |H.E. d.. .g.z...|
-00000020  25 b1 53 94 27 78 ed ae  58 2f 1b 00 00 04 00 2f  |%.S.'x..X/...../|
-00000030  00 ff 01 00 00 3d 00 00  00 10 00 0e 00 00 0b 73  |.....=.........s|
-00000040  6e 69 74 65 73 74 2e 63  6f 6d 00 0d 00 20 00 1e  |nitest.com... ..|
-00000050  06 01 06 02 06 03 05 01  05 02 05 03 04 01 04 02  |................|
-00000060  04 03 03 01 03 02 03 03  02 01 02 02 02 03 00 0f  |................|
-00000070  00 01 01                                          |...|
+00000000  16 03 01 00 6f 01 00 00  6b 03 03 64 29 6e 67 3d  |....o...k..d)ng=|
+00000010  5a 13 48 8a ae a5 67 6b  2f 5b 76 d2 c1 df 23 c6  |Z.H...gk/[v...#.|
+00000020  f9 52 26 33 ce 0b 03 f6  53 a7 db 00 00 04 00 2f  |.R&3....S....../|
+00000030  00 ff 02 01 00 00 3d 00  00 00 10 00 0e 00 00 0b  |......=.........|
+00000040  73 6e 69 74 65 73 74 2e  63 6f 6d 00 0d 00 20 00  |snitest.com... .|
+00000050  1e 06 01 06 02 06 03 05  01 05 02 05 03 04 01 04  |................|
+00000060  02 04 03 03 01 03 02 03  03 02 01 02 02 02 03 00  |................|
+00000070  0f 00 01 01                                       |....|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000230  2c 65 25 d6 52 b6 e3 18  45 bd cc 16 03 03 00 04  |,e%.R...E.......|
 00000240  0e 00 00 00                                       |....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 72 23 e9 89 70  |...........r#..p|
-00000010  97 02 08 58 0d 28 96 5b  19 73 dd 4f 6e 4c 11 dd  |...X.(.[.s.OnL..|
-00000020  cb 56 14 f4 8f c8 e5 84  03 f5 7e f0 a4 08 44 8c  |.V........~...D.|
-00000030  22 74 01 5c e4 9d e0 38  53 90 66 e3 df bb 09 a8  |"t.\...8S.f.....|
-00000040  11 97 0a 44 01 d2 70 85  14 a1 9a 2f 02 34 40 6d  |...D..p..../.4@m|
-00000050  66 80 72 9a 97 98 5c 91  0e dc 42 ac c2 90 2f 30  |f.r...\...B.../0|
-00000060  ca 39 25 94 da 6e b6 5f  94 a9 94 66 7f 32 6a bb  |.9%..n._...f.2j.|
-00000070  5d 43 20 c3 74 f7 52 29  1f d5 62 6b a4 a1 8c 25  |]C .t.R)..bk...%|
-00000080  46 69 22 a5 68 54 f4 68  30 e2 52 14 03 03 00 01  |Fi".hT.h0.R.....|
-00000090  01 16 03 03 00 40 51 d2  78 64 e3 59 ee b7 5f 95  |.....@Q.xd.Y.._.|
-000000a0  4c 49 7f 0d 49 3f 55 71  8c 3b 24 e3 81 22 4a d1  |LI..I?Uq.;$.."J.|
-000000b0  ab 84 4e df 02 9d 56 ea  2a 14 71 e1 dc 1d 5c 1d  |..N...V.*.q...\.|
-000000c0  54 ce cb 58 f6 4d e7 73  44 0d 99 95 a5 2d 7c 2f  |T..X.M.sD....-|/|
-000000d0  15 f5 8f fd 97 40                                 |.....@|
+00000000  16 03 03 00 86 10 00 00  82 00 80 7b 3b b8 73 f0  |...........{;.s.|
+00000010  78 2c 75 91 ee 4a ac 6e  9d 08 8e ef dd 52 fb 38  |x,u..J.n.....R.8|
+00000020  d7 6f b3 39 8a 8c 3c dc  4b e0 a9 2b 0b de 9a d6  |.o.9..<.K..+....|
+00000030  38 72 ae 0f 76 87 4b f6  45 17 f6 fa b2 5a 07 30  |8r..v.K.E....Z.0|
+00000040  5b ef e7 40 e0 95 98 bf  8d 8d 5e 7a 6a ea 2d 2e  |[..@......^zj.-.|
+00000050  9c 99 e4 47 6b 4f 16 32  fb 0d a7 01 36 2e 06 f2  |...GkO.2....6...|
+00000060  65 74 b6 ed 07 51 60 7a  98 d6 77 36 f4 c7 f6 b1  |et...Q`z..w6....|
+00000070  f1 6a 3e 38 7c 79 5c c6  b4 53 5c 85 fb 0b 2c f9  |.j>8|y\..S\...,.|
+00000080  2c 60 97 c8 73 f7 22 ef  52 4c 10 14 03 03 00 01  |,`..s.".RL......|
+00000090  01 16 03 03 00 40 4c 73  6e 5e 66 9d 53 2e fa b7  |.....@Lsn^f.S...|
+000000a0  90 2d 52 55 13 d2 67 28  aa 1a 6f 62 42 ef 2f 4d  |.-RU..g(..obB./M|
+000000b0  04 1d ef 64 8f 1a 70 c0  d0 bf 06 72 ee db 3e 43  |...d..p....r..>C|
+000000c0  7f ed 37 bb a1 62 0c c5  c8 a9 c0 51 8f 77 95 b3  |..7..b.....Q.w..|
+000000d0  72 7e 01 89 c4 32                                 |r~...2|
 >>> Flow 4 (server to client)
 00000000  15 03 03 00 02 02 14                              |.......|
index 0b1c3778ad41ec4950b708f6005cfd6dd568b9c5..4bedd7682d3600ddaf04e3a8ded5de9af113fab0 100644 (file)
@@ -5,6 +5,11 @@
 // Package tls partially implements TLS 1.2, as specified in RFC 5246.
 package tls
 
+// BUG(agl): The crypto/tls package does not implement countermeasures
+// against Lucky13 attacks on CBC-mode encryption. See
+// http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and
+// https://www.imperialviolet.org/2013/02/04/luckythirteen.html.
+
 import (
        "crypto"
        "crypto/ecdsa"
@@ -12,6 +17,7 @@ import (
        "crypto/x509"
        "encoding/pem"
        "errors"
+       "fmt"
        "io/ioutil"
        "net"
        "strings"
@@ -20,8 +26,8 @@ import (
 
 // Server returns a new TLS server side connection
 // using conn as the underlying transport.
-// The configuration config must be non-nil and must have
-// at least one certificate.
+// The configuration config must be non-nil and must include
+// at least one certificate or else set GetCertificate.
 func Server(conn net.Conn, config *Config) *Conn {
        return &Conn{conn: conn, config: config}
 }
@@ -53,8 +59,8 @@ func (l *listener) Accept() (c net.Conn, err error) {
 
 // NewListener creates a Listener which accepts connections from an inner
 // Listener and wraps each connection with Server.
-// The configuration config must be non-nil and must have
-// at least one certificate.
+// The configuration config must be non-nil and must include
+// at least one certificate or else set GetCertificate.
 func NewListener(inner net.Listener, config *Config) net.Listener {
        l := new(listener)
        l.Listener = inner
@@ -64,11 +70,11 @@ func NewListener(inner net.Listener, config *Config) net.Listener {
 
 // Listen creates a TLS listener accepting connections on the
 // given network address using net.Listen.
-// The configuration config must be non-nil and must have
-// at least one certificate.
+// The configuration config must be non-nil and must include
+// at least one certificate or else set GetCertificate.
 func Listen(network, laddr string, config *Config) (net.Listener, error) {
-       if config == nil || len(config.Certificates) == 0 {
-               return nil, errors.New("tls.Listen: no certificates in configuration")
+       if config == nil || (len(config.Certificates) == 0 && config.GetCertificate == nil) {
+               return nil, errors.New("tls: neither Certificates nor GetCertificate set in Config")
        }
        l, err := net.Listen(network, laddr)
        if err != nil {
@@ -166,7 +172,9 @@ func Dial(network, addr string, config *Config) (*Conn, error) {
 }
 
 // LoadX509KeyPair reads and parses a public/private key pair from a pair of
-// files. The files must contain PEM encoded data.
+// files. The files must contain PEM encoded data. On successful return,
+// Certificate.Leaf will be nil because the parsed form of the certificate is
+// not retained.
 func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) {
        certPEMBlock, err := ioutil.ReadFile(certFile)
        if err != nil {
@@ -180,34 +188,53 @@ func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) {
 }
 
 // X509KeyPair parses a public/private key pair from a pair of
-// PEM encoded data.
+// PEM encoded data. On successful return, Certificate.Leaf will be nil because
+// the parsed form of the certificate is not retained.
 func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
-       var cert Certificate
-       var certDERBlock *pem.Block
        fail := func(err error) (Certificate, error) { return Certificate{}, err }
+
+       var cert Certificate
+       var skippedBlockTypes []string
        for {
+               var certDERBlock *pem.Block
                certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
                if certDERBlock == nil {
                        break
                }
                if certDERBlock.Type == "CERTIFICATE" {
                        cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
+               } else {
+                       skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type)
                }
        }
 
        if len(cert.Certificate) == 0 {
-               return fail(errors.New("crypto/tls: failed to parse certificate PEM data"))
+               if len(skippedBlockTypes) == 0 {
+                       return fail(errors.New("crypto/tls: failed to find any PEM data in certificate input"))
+               } else if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") {
+                       return fail(errors.New("crypto/tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched"))
+               } else {
+                       return fail(fmt.Errorf("crypto/tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
+               }
        }
 
+       skippedBlockTypes = skippedBlockTypes[:0]
        var keyDERBlock *pem.Block
        for {
                keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock)
                if keyDERBlock == nil {
-                       return fail(errors.New("crypto/tls: failed to parse key PEM data"))
+                       if len(skippedBlockTypes) == 0 {
+                               return fail(errors.New("crypto/tls: failed to find any PEM data in key input"))
+                       } else if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" {
+                               return fail(errors.New("crypto/tls: found a certificate rather than a key in the PEM for the private key"))
+                       } else {
+                               return fail(fmt.Errorf("crypto/tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
+                       }
                }
                if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") {
                        break
                }
+               skippedBlockTypes = append(skippedBlockTypes, keyDERBlock.Type)
        }
 
        var err error
index c45c10378d76344ed34e1795fbec10391a628ebe..5cc14278a06806eb0512a533f17f4458c81c7409 100644 (file)
@@ -6,6 +6,7 @@ package tls
 
 import (
        "bytes"
+       "errors"
        "fmt"
        "internal/testenv"
        "io"
@@ -104,6 +105,38 @@ func TestX509KeyPair(t *testing.T) {
        }
 }
 
+func TestX509KeyPairErrors(t *testing.T) {
+       _, err := X509KeyPair([]byte(rsaKeyPEM), []byte(rsaCertPEM))
+       if err == nil {
+               t.Fatalf("X509KeyPair didn't return an error when arguments were switched")
+       }
+       if subStr := "been switched"; !strings.Contains(err.Error(), subStr) {
+               t.Fatalf("Expected %q in the error when switching arguments to X509KeyPair, but the error was %q", subStr, err)
+       }
+
+       _, err = X509KeyPair([]byte(rsaCertPEM), []byte(rsaCertPEM))
+       if err == nil {
+               t.Fatalf("X509KeyPair didn't return an error when both arguments were certificates")
+       }
+       if subStr := "certificate"; !strings.Contains(err.Error(), subStr) {
+               t.Fatalf("Expected %q in the error when both arguments to X509KeyPair were certificates, but the error was %q", subStr, err)
+       }
+
+       const nonsensePEM = `
+-----BEGIN NONSENSE-----
+Zm9vZm9vZm9v
+-----END NONSENSE-----
+`
+
+       _, err = X509KeyPair([]byte(nonsensePEM), []byte(nonsensePEM))
+       if err == nil {
+               t.Fatalf("X509KeyPair didn't return an error when both arguments were nonsense")
+       }
+       if subStr := "NONSENSE"; !strings.Contains(err.Error(), subStr) {
+               t.Fatalf("Expected %q in the error when both arguments to X509KeyPair were nonsense, but the error was %q", subStr, err)
+       }
+}
+
 func TestX509MixedKeyPair(t *testing.T) {
        if _, err := X509KeyPair([]byte(rsaCertPEM), []byte(ecdsaKeyPEM)); err == nil {
                t.Error("Load of RSA certificate succeeded with ECDSA private key")
@@ -332,3 +365,104 @@ func TestVerifyHostnameResumed(t *testing.T) {
                c.Close()
        }
 }
+
+func TestConnCloseBreakingWrite(t *testing.T) {
+       ln := newLocalListener(t)
+       defer ln.Close()
+
+       srvCh := make(chan *Conn, 1)
+       var serr error
+       var sconn net.Conn
+       go func() {
+               var err error
+               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
+       }()
+
+       cconn, err := net.Dial("tcp", ln.Addr().String())
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer cconn.Close()
+
+       conn := &changeImplConn{
+               Conn: cconn,
+       }
+
+       clientConfig := *testConfig
+       tconn := Client(conn, &clientConfig)
+       if err := tconn.Handshake(); err != nil {
+               t.Fatal(err)
+       }
+
+       srv := <-srvCh
+       if srv == nil {
+               t.Fatal(serr)
+       }
+       defer sconn.Close()
+
+       connClosed := make(chan struct{})
+       conn.closeFunc = func() error {
+               close(connClosed)
+               return nil
+       }
+
+       inWrite := make(chan bool, 1)
+       var errConnClosed = errors.New("conn closed for test")
+       conn.writeFunc = func(p []byte) (n int, err error) {
+               inWrite <- true
+               <-connClosed
+               return 0, errConnClosed
+       }
+
+       closeReturned := make(chan bool, 1)
+       go func() {
+               <-inWrite
+               tconn.Close() // test that this doesn't block forever.
+               closeReturned <- true
+       }()
+
+       _, err = tconn.Write([]byte("foo"))
+       if err != errConnClosed {
+               t.Errorf("Write error = %v; want errConnClosed", err)
+       }
+
+       <-closeReturned
+       if err := tconn.Close(); err != errClosed {
+               t.Errorf("Close error = %v; want errClosed", err)
+       }
+}
+
+// changeImplConn is a net.Conn which can change its Write and Close
+// methods.
+type changeImplConn struct {
+       net.Conn
+       writeFunc func([]byte) (int, error)
+       closeFunc func() error
+}
+
+func (w *changeImplConn) Write(p []byte) (n int, err error) {
+       if w.writeFunc != nil {
+               return w.writeFunc(p)
+       }
+       return w.Conn.Write(p)
+}
+
+func (w *changeImplConn) Close() error {
+       if w.closeFunc != nil {
+               return w.closeFunc()
+       }
+       return w.Conn.Close()
+}
index 5add4e5d3e0d0d5aab1a6be905fd2f6a68383bf6..1b3e3c0440e9de6c123e865621e25c225ac4b92b 100644 (file)
@@ -129,12 +129,12 @@ func (n Name) appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentif
 
 func (n Name) ToRDNSequence() (ret RDNSequence) {
        ret = n.appendRDNs(ret, n.Country, oidCountry)
-       ret = n.appendRDNs(ret, n.Organization, oidOrganization)
-       ret = n.appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
-       ret = n.appendRDNs(ret, n.Locality, oidLocality)
        ret = n.appendRDNs(ret, n.Province, oidProvince)
+       ret = n.appendRDNs(ret, n.Locality, oidLocality)
        ret = n.appendRDNs(ret, n.StreetAddress, oidStreetAddress)
        ret = n.appendRDNs(ret, n.PostalCode, oidPostalCode)
+       ret = n.appendRDNs(ret, n.Organization, oidOrganization)
+       ret = n.appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
        if len(n.CommonName) > 0 {
                ret = n.appendRDNs(ret, []string{n.CommonName}, oidCommonName)
        }
index 8d3b2fbb23395dc7bbd455fa457a419f27aa830c..9f06f9dabbe67781e8799654724b759c3f5697d1 100644 (file)
@@ -11,6 +11,7 @@ import "io/ioutil"
 // Possible directories with certificate files; stop after successfully
 // reading at least one file from a directory.
 var certDirectories = []string{
+       "/etc/ssl/certs",               // SLES10/SLES11, https://golang.org/issue/12139
        "/system/etc/security/cacerts", // Android
 }
 
index c4d7ab68f7dbbb9d7cb8d8f5217f74c3e34caf83..1424dea99e57033bffaa0e972d13e6463a898e8e 100644 (file)
@@ -39,9 +39,14 @@ func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error) {
        if !ok {
                return nil, errors.New("x509: unknown elliptic curve")
        }
+
+       privateKeyBytes := key.D.Bytes()
+       paddedPrivateKey := make([]byte, (key.Curve.Params().N.BitLen()+7)/8)
+       copy(paddedPrivateKey[len(paddedPrivateKey)-len(privateKeyBytes):], privateKeyBytes)
+
        return asn1.Marshal(ecPrivateKey{
                Version:       1,
-               PrivateKey:    key.D.Bytes(),
+               PrivateKey:    paddedPrivateKey,
                NamedCurveOID: oid,
                PublicKey:     asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)},
        })
@@ -71,13 +76,30 @@ func parseECPrivateKey(namedCurveOID *asn1.ObjectIdentifier, der []byte) (key *e
        }
 
        k := new(big.Int).SetBytes(privKey.PrivateKey)
-       if k.Cmp(curve.Params().N) >= 0 {
+       curveOrder := curve.Params().N
+       if k.Cmp(curveOrder) >= 0 {
                return nil, errors.New("x509: invalid elliptic curve private key value")
        }
        priv := new(ecdsa.PrivateKey)
        priv.Curve = curve
        priv.D = k
-       priv.X, priv.Y = curve.ScalarBaseMult(privKey.PrivateKey)
+
+       privateKey := make([]byte, (curveOrder.BitLen()+7)/8)
+
+       // Some private keys have leading zero padding. This is invalid
+       // according to [SEC1], but this code will ignore it.
+       for len(privKey.PrivateKey) > len(privateKey) {
+               if privKey.PrivateKey[0] != 0 {
+                       return nil, errors.New("x509: invalid private key length")
+               }
+               privKey.PrivateKey = privKey.PrivateKey[1:]
+       }
+
+       // Some private keys remove all leading zeros, this is also invalid
+       // according to [SEC1] but since OpenSSL used to do this, we ignore
+       // this too.
+       copy(privateKey[len(privateKey)-len(privKey.PrivateKey):], privKey.PrivateKey)
+       priv.X, priv.Y = curve.ScalarBaseMult(privateKey)
 
        return priv, nil
 }
index 95f18e77de0e4d58aaa10e98d42b8c3657029c28..55b76d6c38160464040fcb33ac15b0854bcea5e8 100644 (file)
@@ -10,21 +10,35 @@ import (
        "testing"
 )
 
-// Generated using:
-//   openssl ecparam -genkey -name secp384r1 -outform PEM
-var ecPrivateKeyHex = `3081a40201010430bdb9839c08ee793d1157886a7a758a3c8b2a17a4df48f17ace57c72c56b4723cf21dcda21d4e1ad57ff034f19fcfd98ea00706052b81040022a16403620004feea808b5ee2429cfcce13c32160e1c960990bd050bb0fdf7222f3decd0a55008e32a6aa3c9062051c4cba92a7a3b178b24567412d43cdd2f882fa5addddd726fe3e208d2c26d733a773a597abb749714df7256ead5105fa6e7b3650de236b50`
+var ecKeyTests = []struct {
+       derHex            string
+       shouldReserialize bool
+}{
+       // Generated using:
+       //   openssl ecparam -genkey -name secp384r1 -outform PEM
+       {"3081a40201010430bdb9839c08ee793d1157886a7a758a3c8b2a17a4df48f17ace57c72c56b4723cf21dcda21d4e1ad57ff034f19fcfd98ea00706052b81040022a16403620004feea808b5ee2429cfcce13c32160e1c960990bd050bb0fdf7222f3decd0a55008e32a6aa3c9062051c4cba92a7a3b178b24567412d43cdd2f882fa5addddd726fe3e208d2c26d733a773a597abb749714df7256ead5105fa6e7b3650de236b50", true},
+       // This key was generated by GnuTLS and has illegal zero-padding of the
+       // private key. See https://github.com/golang/go/issues/13699.
+       {"3078020101042100f9f43a04b9bdc3ab01f53be6df80e7a7bc3eaf7b87fc24e630a4a0aa97633645a00a06082a8648ce3d030107a1440342000441a51bc318461b4c39a45048a16d4fc2a935b1ea7fe86e8c1fa219d6f2438f7c7fd62957d3442efb94b6a23eb0ea66dda663dc42f379cda6630b21b7888a5d3d", false},
+       // This was generated using an old version of OpenSSL and is missing a
+       // leading zero byte in the private key that should be present.
+       {"3081db0201010441607b4f985774ac21e633999794542e09312073480baa69550914d6d43d8414441e61b36650567901da714f94dffb3ce0e2575c31928a0997d51df5c440e983ca17a00706052b81040023a181890381860004001661557afedd7ac8d6b70e038e576558c626eb62edda36d29c3a1310277c11f67a8c6f949e5430a37dcfb95d902c1b5b5379c389873b9dd17be3bdb088a4774a7401072f830fb9a08d93bfa50a03dd3292ea07928724ddb915d831917a338f6b0aecfbc3cf5352c4a1295d356890c41c34116d29eeb93779aab9d9d78e2613437740f6", false},
+}
 
 func TestParseECPrivateKey(t *testing.T) {
-       derBytes, _ := hex.DecodeString(ecPrivateKeyHex)
-       key, err := ParseECPrivateKey(derBytes)
-       if err != nil {
-               t.Errorf("failed to decode EC private key: %s", err)
-       }
-       serialized, err := MarshalECPrivateKey(key)
-       if err != nil {
-               t.Fatalf("failed to encode EC private key: %s", err)
-       }
-       if !bytes.Equal(serialized, derBytes) {
-               t.Fatalf("serialized key differs: got %x, want %x", serialized, derBytes)
+       for i, test := range ecKeyTests {
+               derBytes, _ := hex.DecodeString(test.derHex)
+               key, err := ParseECPrivateKey(derBytes)
+               if err != nil {
+                       t.Fatalf("#%d: failed to decode EC private key: %s", i, err)
+               }
+               serialized, err := MarshalECPrivateKey(key)
+               if err != nil {
+                       t.Fatalf("#%d: failed to encode EC private key: %s", i, err)
+               }
+               matches := bytes.Equal(serialized, derBytes)
+               if matches != test.shouldReserialize {
+                       t.Fatalf("#%d: when serializing key: matches=%t, should match=%t: original %x, reserialized %x", i, matches, test.shouldReserialize, serialized, derBytes)
+               }
        }
 }
index 21b870c1712cc712ed3c2dc89baa37af9ccce1c8..27e9bbfbcc6029392b048cd95e80c4162925b343 100644 (file)
@@ -5,6 +5,7 @@
 package x509
 
 import (
+       "errors"
        "fmt"
        "net"
        "runtime"
@@ -122,6 +123,10 @@ func (SystemRootsError) Error() string {
        return "x509: failed to load system roots and no roots provided"
 }
 
+// errNotParsed is returned when a certificate without ASN.1 contents is
+// verified. Platform-specific verification needs the ASN.1 contents.
+var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate")
+
 // VerifyOptions contains parameters for Certificate.Verify. It's a structure
 // because other PKIX verification APIs have ended up needing many options.
 type VerifyOptions struct {
@@ -210,6 +215,19 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
 //
 // WARNING: this doesn't do any revocation checking.
 func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
+       // Platform-specific verification needs the ASN.1 contents so
+       // this makes the behaviour consistent across platforms.
+       if len(c.Raw) == 0 {
+               return nil, errNotParsed
+       }
+       if opts.Intermediates != nil {
+               for _, intermediate := range opts.Intermediates.certs {
+                       if len(intermediate.Raw) == 0 {
+                               return nil, errNotParsed
+                       }
+               }
+       }
+
        // Use Windows's own verification and chain building.
        if opts.Roots == nil && runtime.GOOS == "windows" {
                return c.systemVerify(&opts)
index be6c013464b40eae1a8e881b4aa51ccf7d71dd41..d9288bb30e880f92e0385c155d0796ab22b7b6f1 100644 (file)
@@ -19,6 +19,7 @@ import (
        "encoding/asn1"
        "encoding/pem"
        "errors"
+       "fmt"
        "io"
        "math/big"
        "net"
@@ -56,6 +57,9 @@ func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorith
                        N: pub.N,
                        E: pub.E,
                })
+               if err != nil {
+                       return nil, pkix.AlgorithmIdentifier{}, err
+               }
                publicKeyAlgorithm.Algorithm = oidPublicKeyRSA
                // This is a NULL parameters value which is technically
                // superfluous, but most other code includes it and, by
@@ -171,6 +175,28 @@ const (
        ECDSAWithSHA512
 )
 
+var algoName = [...]string{
+       MD2WithRSA:      "MD2-RSA",
+       MD5WithRSA:      "MD5-RSA",
+       SHA1WithRSA:     "SHA1-RSA",
+       SHA256WithRSA:   "SHA256-RSA",
+       SHA384WithRSA:   "SHA384-RSA",
+       SHA512WithRSA:   "SHA512-RSA",
+       DSAWithSHA1:     "DSA-SHA1",
+       DSAWithSHA256:   "DSA-SHA256",
+       ECDSAWithSHA1:   "ECDSA-SHA1",
+       ECDSAWithSHA256: "ECDSA-SHA256",
+       ECDSAWithSHA384: "ECDSA-SHA384",
+       ECDSAWithSHA512: "ECDSA-SHA512",
+}
+
+func (algo SignatureAlgorithm) String() string {
+       if 0 < algo && int(algo) < len(algoName) {
+               return algoName[algo]
+       }
+       return strconv.Itoa(int(algo))
+}
+
 type PublicKeyAlgorithm int
 
 const (
@@ -538,6 +564,13 @@ type Certificate struct {
 // involves algorithms that are not currently implemented.
 var ErrUnsupportedAlgorithm = errors.New("x509: cannot verify signature: algorithm unimplemented")
 
+// An InsecureAlgorithmError
+type InsecureAlgorithmError SignatureAlgorithm
+
+func (e InsecureAlgorithmError) Error() string {
+       return fmt.Sprintf("x509: cannot verify signature: insecure algorithm %v", SignatureAlgorithm(e))
+}
+
 // ConstraintViolationError results when a requested usage is not permitted by
 // a certificate. For example: checking a signature when the public key isn't a
 // certificate signing key.
@@ -648,6 +681,8 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey
                hashType = crypto.SHA384
        case SHA512WithRSA, ECDSAWithSHA512:
                hashType = crypto.SHA512
+       case MD2WithRSA, MD5WithRSA:
+               return InsecureAlgorithmError(algo)
        default:
                return ErrUnsupportedAlgorithm
        }
@@ -906,10 +941,6 @@ func parseCertificate(in *certificate) (*Certificate, error) {
                return nil, err
        }
 
-       if in.TBSCertificate.SerialNumber.Sign() < 0 {
-               return nil, errors.New("x509: negative serial number")
-       }
-
        out.Version = in.TBSCertificate.Version + 1
        out.SerialNumber = in.TBSCertificate.SerialNumber
 
@@ -1017,7 +1048,7 @@ func parseCertificate(in *certificate) (*Certificate, error) {
                                }
 
                        case 31:
-                               // RFC 5280, 4.2.1.14
+                               // RFC 5280, 4.2.1.13
 
                                // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
                                //
@@ -1038,6 +1069,11 @@ func parseCertificate(in *certificate) (*Certificate, error) {
                                }
 
                                for _, dp := range cdp {
+                                       // Per RFC 5280, 4.2.1.13, one of distributionPoint or cRLIssuer may be empty.
+                                       if len(dp.DistributionPoint.FullName.Bytes) == 0 {
+                                               continue
+                                       }
+
                                        var n asn1.RawValue
                                        if _, err := asn1.Unmarshal(dp.DistributionPoint.FullName.Bytes, &n); err != nil {
                                                return nil, err
@@ -1704,9 +1740,7 @@ type CertificateRequest struct {
 
        Subject pkix.Name
 
-       // Attributes is a collection of attributes providing
-       // additional information about the subject of the certificate.
-       // See RFC 2986 section 4.1.
+       // Attributes is the dried husk of a bug and shouldn't be used.
        Attributes []pkix.AttributeTypeAndValueSET
 
        // Extensions contains raw X.509 extensions. When parsing CSRs, this
@@ -1781,6 +1815,38 @@ func parseRawAttributes(rawAttributes []asn1.RawValue) []pkix.AttributeTypeAndVa
        return attributes
 }
 
+// parseCSRExtensions parses the attributes from a CSR and extracts any
+// requested extensions.
+func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error) {
+       // pkcs10Attribute reflects the Attribute structure from section 4.1 of
+       // https://tools.ietf.org/html/rfc2986.
+       type pkcs10Attribute struct {
+               Id     asn1.ObjectIdentifier
+               Values []asn1.RawValue `asn1:"set"`
+       }
+
+       var ret []pkix.Extension
+       for _, rawAttr := range rawAttributes {
+               var attr pkcs10Attribute
+               if rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr); err != nil || len(rest) != 0 || len(attr.Values) == 0 {
+                       // Ignore attributes that don't parse.
+                       continue
+               }
+
+               if !attr.Id.Equal(oidExtensionRequest) {
+                       continue
+               }
+
+               var extensions []pkix.Extension
+               if _, err := asn1.Unmarshal(attr.Values[0].FullBytes, &extensions); err != nil {
+                       return nil, err
+               }
+               ret = append(ret, extensions...)
+       }
+
+       return ret, nil
+}
+
 // CreateCertificateRequest creates a new certificate based on a template. The
 // following members of template are used: Subject, Attributes,
 // SignatureAlgorithm, Extensions, DNSNames, EmailAddresses, and IPAddresses.
@@ -1983,38 +2049,15 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error
 
        out.Subject.FillFromRDNSequence(&subject)
 
-       var extensions []pkix.AttributeTypeAndValue
-
-       for _, atvSet := range out.Attributes {
-               if !atvSet.Type.Equal(oidExtensionRequest) {
-                       continue
-               }
-
-               for _, atvs := range atvSet.Value {
-                       extensions = append(extensions, atvs...)
-               }
+       if out.Extensions, err = parseCSRExtensions(in.TBSCSR.RawAttributes); err != nil {
+               return nil, err
        }
 
-       out.Extensions = make([]pkix.Extension, 0, len(extensions))
-
-       for _, e := range extensions {
-               value, ok := e.Value.([]byte)
-               if !ok {
-                       return nil, errors.New("x509: extension attribute contained non-OCTET STRING data")
-               }
-
-               out.Extensions = append(out.Extensions, pkix.Extension{
-                       Id:    e.Type,
-                       Value: value,
-               })
-
-               if len(e.Type) == 4 && e.Type[0] == 2 && e.Type[1] == 5 && e.Type[2] == 29 {
-                       switch e.Type[3] {
-                       case 17:
-                               out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(value)
-                               if err != nil {
-                                       return nil, err
-                               }
+       for _, extension := range out.Extensions {
+               if extension.Id.Equal(oidExtensionSubjectAltName) {
+                       out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(extension.Value)
+                       if err != nil {
+                               return nil, err
                        }
                }
        }
index f4f9fa2f7f9e39e322281679a2687181d7459927..d1ef0274bc27e0fbb0ce9cd691e346d7e6c47d60 100644 (file)
@@ -18,6 +18,7 @@ import (
        "encoding/base64"
        "encoding/hex"
        "encoding/pem"
+       "fmt"
        "internal/testenv"
        "math/big"
        "net"
@@ -343,7 +344,11 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
        for _, test := range tests {
                commonName := "test.example.com"
                template := Certificate{
-                       SerialNumber: big.NewInt(1),
+                       // SerialNumber is negative to ensure that negative
+                       // values are parsed. This is due to the prevalence of
+                       // buggy code that produces certificates with negative
+                       // serial numbers.
+                       SerialNumber: big.NewInt(-1),
                        Subject: pkix.Name{
                                CommonName:   commonName,
                                Organization: []string{"Σ Acme Co"},
@@ -504,9 +509,9 @@ func TestUnknownCriticalExtension(t *testing.T) {
 
        oids := []asn1.ObjectIdentifier{
                // This OID is in the PKIX arc, but unknown.
-               asn1.ObjectIdentifier{2, 5, 29, 999999},
+               {2, 5, 29, 999999},
                // This is a nonsense, unassigned OID.
-               asn1.ObjectIdentifier{1, 2, 3, 4},
+               {1, 2, 3, 4},
        }
 
        for _, oid := range oids {
@@ -1074,6 +1079,40 @@ func TestParseCertificateRequest(t *testing.T) {
        }
 }
 
+func TestCriticalFlagInCSRRequestedExtensions(t *testing.T) {
+       // This CSR contains an extension request where the extensions have a
+       // critical flag in them. In the past we failed to handle this.
+       const csrBase64 = "MIICrTCCAZUCAQIwMzEgMB4GA1UEAwwXU0NFUCBDQSBmb3IgRGV2ZWxlciBTcmwxDzANBgNVBAsMBjQzNTk3MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALFMAJ7Zy9YyfgbNlbUWAW0LalNRMPs7aXmLANsCpjhnw3lLlfDPaLeWyKh1nK5I5ojaJOW6KIOSAcJkDUe3rrE0wR0RVt3UxArqs0R/ND3u5Q+bDQY2X1HAFUHzUzcdm5JRAIA355v90teMckaWAIlkRQjDE22Lzc6NAl64KOd1rqOUNj8+PfX6fSo20jm94Pp1+a6mfk3G/RUWVuSm7owO5DZI/Fsi2ijdmb4NUar6K/bDKYTrDFkzcqAyMfP3TitUtBp19Mp3B1yAlHjlbp/r5fSSXfOGHZdgIvp0WkLuK2u5eQrX5l7HMB/5epgUs3HQxKY6ljhh5wAjDwz//LsCAwEAAaA1MDMGCSqGSIb3DQEJDjEmMCQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQEFBQADggEBAAMq3bxJSPQEgzLYR/yaVvgjCDrc3zUbIwdOis6Go06Q4RnjH5yRaSZAqZQTDsPurQcnz2I39VMGEiSkFJFavf4QHIZ7QFLkyXadMtALc87tm17Ej719SbHcBSSZayR9VYJUNXRLayI6HvyUrmqcMKh+iX3WY3ICr59/wlM0tYa8DYN4yzmOa2Onb29gy3YlaF5A2AKAMmk003cRT9gY26mjpv7d21czOSSeNyVIoZ04IR9ee71vWTMdv0hu/af5kSjQ+ZG5/Qgc0+mnECLz/1gtxt1srLYbtYQ/qAY8oX1DCSGFS61tN/vl+4cxGMD/VGcGzADRLRHSlVqy2Qgss6Q="
+
+       csrBytes := fromBase64(csrBase64)
+       csr, err := ParseCertificateRequest(csrBytes)
+       if err != nil {
+               t.Fatalf("failed to parse CSR: %s", err)
+       }
+
+       expected := []struct {
+               Id    asn1.ObjectIdentifier
+               Value []byte
+       }{
+               {oidExtensionBasicConstraints, fromBase64("MAYBAf8CAQA=")},
+               {oidExtensionKeyUsage, fromBase64("AwIChA==")},
+       }
+
+       if n := len(csr.Extensions); n != len(expected) {
+               t.Fatalf("expected to find %d extensions but found %d", len(expected), n)
+       }
+
+       for i, extension := range csr.Extensions {
+               if !extension.Id.Equal(expected[i].Id) {
+                       t.Fatalf("extension #%d has unexpected type %v (expected %v)", i, extension.Id, expected[i].Id)
+               }
+
+               if !bytes.Equal(extension.Value, expected[i].Value) {
+                       t.Fatalf("extension #%d has unexpected contents %x (expected %x)", i, extension.Value, expected[i].Value)
+               }
+       }
+}
+
 func TestMaxPathLen(t *testing.T) {
        block, _ := pem.Decode([]byte(pemPrivateKey))
        rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes)
@@ -1159,6 +1198,29 @@ func TestASN1BitLength(t *testing.T) {
        }
 }
 
+func TestVerifyEmptyCertificate(t *testing.T) {
+       if _, err := new(Certificate).Verify(VerifyOptions{}); err != errNotParsed {
+               t.Errorf("Verifying empty certificate resulted in unexpected error: %q (wanted %q)", err, errNotParsed)
+       }
+}
+
+func TestInsecureAlgorithmErrorString(t *testing.T) {
+       tests := []struct {
+               sa   SignatureAlgorithm
+               want string
+       }{
+               {MD2WithRSA, "x509: cannot verify signature: insecure algorithm MD2-RSA"},
+               {-1, "x509: cannot verify signature: insecure algorithm -1"},
+               {0, "x509: cannot verify signature: insecure algorithm 0"},
+               {9999, "x509: cannot verify signature: insecure algorithm 9999"},
+       }
+       for i, tt := range tests {
+               if got := fmt.Sprint(InsecureAlgorithmError(tt.sa)); got != tt.want {
+                       t.Errorf("%d. mismatch.\n got: %s\nwant: %s\n", i, got, tt.want)
+               }
+       }
+}
+
 // These CSR was generated with OpenSSL:
 //  openssl req -out CSR.csr -new -sha256 -nodes -keyout privateKey.key -config openssl.cnf
 //
@@ -1176,3 +1238,36 @@ var csrBase64Array = [...]string{
        // Both [ v3_req ] and [ req_attributes ]
        "MIIDaTCCAlECAQAwfjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIGA1UEAwwLQ29tbW9uIE5hbWUxITAfBgkqhkiG9w0BCQEWEnRlc3RAZW1haWwuYWRkcmVzczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK1GY4YFx2ujlZEOJxQVYmsjUnLsd5nFVnNpLE4cV+77sgv9NPNlB8uhn3MXt5leD34rm/2BisCHOifPucYlSrszo2beuKhvwn4+2FxDmWtBEMu/QA16L5IvoOfYZm/gJTsPwKDqvaR0tTU67a9OtxwNTBMI56YKtmwd/o8d3hYv9cg+9ZGAZ/gKONcg/OWYx/XRh6bd0g8DMbCikpWgXKDsvvK1Nk+VtkDO1JxuBaj4Lz/p/MifTfnHoqHxWOWl4EaTs4Ychxsv34/rSj1KD1tJqorIv5Xv2aqv4sjxfbrYzX4kvS5SC1goIovLnhj5UjmQ3Qy8u65eow/LLWw+YFcCAwEAAaCBpTAgBgkqhkiG9w0BCQcxEwwRaWdub3JlZCBjaGFsbGVuZ2UwKAYJKoZIhvcNAQkCMRsMGWlnbm9yZWQgdW5zdHJ1Y3R1cmVkIG5hbWUwVwYJKoZIhvcNAQkOMUowSDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAuBgNVHREEJzAlgRFnb3BoZXJAZ29sYW5nLm9yZ4IQdGVzdC5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAgxe2N5O48EMsYE7o0rZBB0wi3Ov5/yYfnmmVI22Y3sP6VXbLDW0+UWIeSccOhzUCcZ/G4qcrfhhx6gTZTeA01nP7TdTJURvWAH5iFqj9sQ0qnLq6nEcVHij3sG6M5+BxAIVClQBk6lTCzgphc835Fjj6qSLuJ20XHdL5UfUbiJxx299CHgyBRL+hBUIPfz8p+ZgamyAuDLfnj54zzcRVyLlrmMLNPZNll1Q70RxoU6uWvLH8wB8vQe3Q/guSGubLyLRTUQVPh+dw1L4t8MKFWfX/48jwRM4gIRHFHPeAAE9D9YAoqdIvj/iFm/eQ++7DP8MDwOZWsXeB6jjwHuLmkQ==",
 }
+
+var md5cert = `
+-----BEGIN CERTIFICATE-----
+MIIB4TCCAUoCCQCfmw3vMgPS5TANBgkqhkiG9w0BAQQFADA1MQswCQYDVQQGEwJB
+VTETMBEGA1UECBMKU29tZS1TdGF0ZTERMA8GA1UEChMITUQ1IEluYy4wHhcNMTUx
+MjAzMTkyOTMyWhcNMjkwODEyMTkyOTMyWjA1MQswCQYDVQQGEwJBVTETMBEGA1UE
+CBMKU29tZS1TdGF0ZTERMA8GA1UEChMITUQ1IEluYy4wgZ8wDQYJKoZIhvcNAQEB
+BQADgY0AMIGJAoGBANrq2nhLQj5mlXbpVX3QUPhfEm/vdEqPkoWtR/jRZIWm4WGf
+Wpq/LKHJx2Pqwn+t117syN8l4U5unyAi1BJSXjBwPZNd7dXjcuJ+bRLV7FZ/iuvs
+cfYyQQFTxan4TaJMd0x1HoNDbNbjHa02IyjjYE/r3mb/PIg+J2t5AZEh80lPAgMB
+AAEwDQYJKoZIhvcNAQEEBQADgYEAjGzp3K3ey/YfKHohf33yHHWd695HQxDAP+wY
+cs9/TAyLR+gJzJP7d18EcDDLJWVi7bhfa4EAD86di05azOh9kWSn4b3o9QYRGCSw
+GNnI3Zk0cwNKA49hZntKKiy22DhRk7JAHF01d6Bu3KkHkmENrtJ+zj/+159WAnUa
+qViorq4=
+-----END CERTIFICATE-----
+`
+
+func TestMD5(t *testing.T) {
+       pemBlock, _ := pem.Decode([]byte(md5cert))
+       cert, err := ParseCertificate(pemBlock.Bytes)
+       if err != nil {
+               t.Fatalf("failed to parse certificate: %s", err)
+       }
+       if sa := cert.SignatureAlgorithm; sa != MD5WithRSA {
+               t.Errorf("signature algorithm is %v, want %v", sa, MD5WithRSA)
+       }
+       if err = cert.CheckSignatureFrom(cert); err == nil {
+               t.Fatalf("certificate verification succeeded incorrectly")
+       }
+       if _, ok := err.(InsecureAlgorithmError); !ok {
+               t.Fatalf("certificate verification returned %v (%T), wanted InsecureAlgorithmError", err, err)
+       }
+}
index c0b38a24940fcade4452df0b5cdae6369420d3df..740fd9d6e7c9af2a82a0f0d297e53b70d92e2d2e 100644 (file)
@@ -12,6 +12,7 @@ import (
        "fmt"
        "reflect"
        "strconv"
+       "time"
 )
 
 var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
@@ -127,6 +128,18 @@ func convertAssign(dest, src interface{}) error {
                        *d = s
                        return nil
                }
+       case time.Time:
+               switch d := dest.(type) {
+               case *string:
+                       *d = s.Format(time.RFC3339Nano)
+                       return nil
+               case *[]byte:
+                       if d == nil {
+                               return errNilPtr
+                       }
+                       *d = []byte(s.Format(time.RFC3339Nano))
+                       return nil
+               }
        case nil:
                switch d := dest.(type) {
                case *interface{}:
@@ -203,11 +216,16 @@ func convertAssign(dest, src interface{}) error {
        }
 
        dv := reflect.Indirect(dpv)
-       if dv.Kind() == sv.Kind() {
+       if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
                dv.Set(sv)
                return nil
        }
 
+       if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
+               dv.Set(sv.Convert(dv.Type()))
+               return nil
+       }
+
        switch dv.Kind() {
        case reflect.Ptr:
                if src == nil {
@@ -221,7 +239,8 @@ func convertAssign(dest, src interface{}) error {
                s := asString(src)
                i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
                if err != nil {
-                       return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err)
+                       err = strconvErr(err)
+                       return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
                }
                dv.SetInt(i64)
                return nil
@@ -229,7 +248,8 @@ func convertAssign(dest, src interface{}) error {
                s := asString(src)
                u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
                if err != nil {
-                       return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err)
+                       err = strconvErr(err)
+                       return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
                }
                dv.SetUint(u64)
                return nil
@@ -237,13 +257,21 @@ func convertAssign(dest, src interface{}) error {
                s := asString(src)
                f64, err := strconv.ParseFloat(s, dv.Type().Bits())
                if err != nil {
-                       return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err)
+                       err = strconvErr(err)
+                       return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
                }
                dv.SetFloat(f64)
                return nil
        }
 
-       return fmt.Errorf("unsupported driver -> Scan pair: %T -> %T", src, dest)
+       return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
+}
+
+func strconvErr(err error) error {
+       if ne, ok := err.(*strconv.NumError); ok {
+               return ne.Err
+       }
+       return err
 }
 
 func cloneBytes(b []byte) []byte {
index 98af9fb64c58ba39dcadfe9ae2b1e7e6eeb37ea1..342875e190c99ed12baf1e14d720e8b512e9526b 100644 (file)
@@ -16,23 +16,28 @@ import (
 var someTime = time.Unix(123, 0)
 var answer int64 = 42
 
+type userDefined float64
+
+type userDefinedSlice []int
+
 type conversionTest struct {
        s, d interface{} // source and destination
 
        // following are used if they're non-zero
-       wantint   int64
-       wantuint  uint64
-       wantstr   string
-       wantbytes []byte
-       wantraw   RawBytes
-       wantf32   float32
-       wantf64   float64
-       wanttime  time.Time
-       wantbool  bool // used if d is of type *bool
-       wanterr   string
-       wantiface interface{}
-       wantptr   *int64 // if non-nil, *d's pointed value must be equal to *wantptr
-       wantnil   bool   // if true, *d must be *int64(nil)
+       wantint    int64
+       wantuint   uint64
+       wantstr    string
+       wantbytes  []byte
+       wantraw    RawBytes
+       wantf32    float32
+       wantf64    float64
+       wanttime   time.Time
+       wantbool   bool // used if d is of type *bool
+       wanterr    string
+       wantiface  interface{}
+       wantptr    *int64 // if non-nil, *d's pointed value must be equal to *wantptr
+       wantnil    bool   // if true, *d must be *int64(nil)
+       wantusrdef userDefined
 }
 
 // Target variables for scanning into.
@@ -72,6 +77,14 @@ var conversionTests = []conversionTest{
        {s: uint64(123), d: &scanstr, wantstr: "123"},
        {s: 1.5, d: &scanstr, wantstr: "1.5"},
 
+       // From time.Time:
+       {s: time.Unix(1, 0).UTC(), d: &scanstr, wantstr: "1970-01-01T00:00:01Z"},
+       {s: time.Unix(1453874597, 0).In(time.FixedZone("here", -3600*8)), d: &scanstr, wantstr: "2016-01-26T22:03:17-08:00"},
+       {s: time.Unix(1, 2).UTC(), d: &scanstr, wantstr: "1970-01-01T00:00:01.000000002Z"},
+       {s: time.Time{}, d: &scanstr, wantstr: "0001-01-01T00:00:00Z"},
+       {s: time.Unix(1, 2).UTC(), d: &scanbytes, wantbytes: []byte("1970-01-01T00:00:01.000000002Z")},
+       {s: time.Unix(1, 2).UTC(), d: &scaniface, wantiface: time.Unix(1, 2).UTC()},
+
        // To []byte
        {s: nil, d: &scanbytes, wantbytes: nil},
        {s: "string", d: &scanbytes, wantbytes: []byte("string")},
@@ -99,10 +112,16 @@ var conversionTests = []conversionTest{
 
        // Strings to integers
        {s: "255", d: &scanuint8, wantuint: 255},
-       {s: "256", d: &scanuint8, wanterr: `converting string "256" to a uint8: strconv.ParseUint: parsing "256": value out of range`},
+       {s: "256", d: &scanuint8, wanterr: "converting driver.Value type string (\"256\") to a uint8: value out of range"},
        {s: "256", d: &scanuint16, wantuint: 256},
        {s: "-1", d: &scanint, wantint: -1},
-       {s: "foo", d: &scanint, wanterr: `converting string "foo" to a int: strconv.ParseInt: parsing "foo": invalid syntax`},
+       {s: "foo", d: &scanint, wanterr: "converting driver.Value type string (\"foo\") to a int: invalid syntax"},
+
+       // int64 to smaller integers
+       {s: int64(5), d: &scanuint8, wantuint: 5},
+       {s: int64(256), d: &scanuint8, wanterr: "converting driver.Value type int64 (\"256\") to a uint8: value out of range"},
+       {s: int64(256), d: &scanuint16, wantuint: 256},
+       {s: int64(65536), d: &scanuint16, wanterr: "converting driver.Value type int64 (\"65536\") to a uint16: value out of range"},
 
        // True bools
        {s: true, d: &scanbool, wantbool: true},
@@ -145,6 +164,15 @@ var conversionTests = []conversionTest{
        {s: true, d: &scaniface, wantiface: true},
        {s: nil, d: &scaniface},
        {s: []byte(nil), d: &scaniface, wantiface: []byte(nil)},
+
+       // To a user-defined type
+       {s: 1.5, d: new(userDefined), wantusrdef: 1.5},
+       {s: int64(123), d: new(userDefined), wantusrdef: 123},
+       {s: "1.5", d: new(userDefined), wantusrdef: 1.5},
+       {s: []byte{1, 2, 3}, d: new(userDefinedSlice), wanterr: `unsupported Scan, storing driver.Value type []uint8 into type *sql.userDefinedSlice`},
+
+       // Other errors
+       {s: complex(1, 2), d: &scanstr, wanterr: `unsupported Scan, storing driver.Value type complex128 into type *string`},
 }
 
 func intPtrValue(intptr interface{}) interface{} {
@@ -228,6 +256,9 @@ func TestConversions(t *testing.T) {
                                }
                        }
                }
+               if ct.wantusrdef != 0 && ct.wantusrdef != *ct.d.(*userDefined) {
+                       errf("want userDefined %f, got %f", ct.wantusrdef, *ct.d.(*userDefined))
+               }
        }
 }
 
index 3305354dfd0d66183d96545bbae100d8c3d52450..bc547849897be063b15fdce16175e93f1d3672dc 100644 (file)
@@ -200,10 +200,15 @@ func IsScanValue(v interface{}) bool {
 // ValueConverter that's used when a Stmt doesn't implement
 // ColumnConverter.
 //
-// DefaultParameterConverter returns the given value directly if
-// IsValue(value).  Otherwise integer type are converted to
-// int64, floats to float64, and strings to []byte.  Other types are
-// an error.
+// DefaultParameterConverter returns its argument directly if
+// IsValue(arg). Otherwise, if the argument implements Valuer, its
+// Value method is used to return a Value. As a fallback, the provided
+// argument's underlying type is used to convert it to a Value:
+// underlying integer types are converted to int64, floats to float64,
+// and strings to []byte. If the argument is a nil pointer,
+// ConvertValue returns a nil Value. If the argument is a non-nil
+// pointer, it is dereferenced and ConvertValue is called
+// recursively. Other types are an error.
 var DefaultParameterConverter defaultConverter
 
 type defaultConverter struct{}
index 8cbbb29a7c24e025019ec7e055f4ada0b0d12ac9..b5ff1213587085bed3fe3237b5a575ad701a5b35 100644 (file)
@@ -33,6 +33,9 @@ var _ = log.Printf
 //   INSERT|<tablename>|col=val,col2=val2,col3=?
 //   SELECT|<tablename>|projectcol1,projectcol2|filtercol=?,filtercol2=?
 //
+// Any of these can be preceded by PANIC|<method>|, to cause the
+// named method on fakeStmt to panic.
+//
 // When opening a fakeDriver's database, it starts empty with no
 // tables.  All tables and data are stored in memory only.
 type fakeDriver struct {
@@ -111,6 +114,7 @@ type fakeStmt struct {
 
        cmd   string
        table string
+       panic string
 
        closed bool
 
@@ -153,12 +157,32 @@ func TestDrivers(t *testing.T) {
        }
 }
 
+// hook to simulate connection failures
+var hookOpenErr struct {
+       sync.Mutex
+       fn func() error
+}
+
+func setHookOpenErr(fn func() error) {
+       hookOpenErr.Lock()
+       defer hookOpenErr.Unlock()
+       hookOpenErr.fn = fn
+}
+
 // Supports dsn forms:
 //    <dbname>
 //    <dbname>;<opts>  (only currently supported option is `badConn`,
 //                      which causes driver.ErrBadConn to be returned on
 //                      every other conn.Begin())
 func (d *fakeDriver) Open(dsn string) (driver.Conn, error) {
+       hookOpenErr.Lock()
+       fn := hookOpenErr.fn
+       hookOpenErr.Unlock()
+       if fn != nil {
+               if err := fn(); err != nil {
+                       return nil, err
+               }
+       }
        parts := strings.Split(dsn, ";")
        if len(parts) < 1 {
                return nil, errors.New("fakedb: no database name")
@@ -479,9 +503,15 @@ func (c *fakeConn) Prepare(query string) (driver.Stmt, error) {
        if len(parts) < 1 {
                return nil, errf("empty query")
        }
+       stmt := &fakeStmt{q: query, c: c}
+       if len(parts) >= 3 && parts[0] == "PANIC" {
+               stmt.panic = parts[1]
+               parts = parts[2:]
+       }
        cmd := parts[0]
+       stmt.cmd = cmd
        parts = parts[1:]
-       stmt := &fakeStmt{q: query, c: c, cmd: cmd}
+
        c.incrStat(&c.stmtsMade)
        switch cmd {
        case "WIPE":
@@ -504,6 +534,9 @@ func (c *fakeConn) Prepare(query string) (driver.Stmt, error) {
 }
 
 func (s *fakeStmt) ColumnConverter(idx int) driver.ValueConverter {
+       if s.panic == "ColumnConverter" {
+               panic(s.panic)
+       }
        if len(s.placeholderConverter) == 0 {
                return driver.DefaultParameterConverter
        }
@@ -511,6 +544,9 @@ func (s *fakeStmt) ColumnConverter(idx int) driver.ValueConverter {
 }
 
 func (s *fakeStmt) Close() error {
+       if s.panic == "Close" {
+               panic(s.panic)
+       }
        if s.c == nil {
                panic("nil conn in fakeStmt.Close")
        }
@@ -530,6 +566,9 @@ var errClosed = errors.New("fakedb: statement has been closed")
 var hookExecBadConn func() bool
 
 func (s *fakeStmt) Exec(args []driver.Value) (driver.Result, error) {
+       if s.panic == "Exec" {
+               panic(s.panic)
+       }
        if s.closed {
                return nil, errClosed
        }
@@ -614,6 +653,9 @@ func (s *fakeStmt) execInsert(args []driver.Value, doInsert bool) (driver.Result
 var hookQueryBadConn func() bool
 
 func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) {
+       if s.panic == "Query" {
+               panic(s.panic)
+       }
        if s.closed {
                return nil, errClosed
        }
@@ -696,16 +738,31 @@ rows:
 }
 
 func (s *fakeStmt) NumInput() int {
+       if s.panic == "NumInput" {
+               panic(s.panic)
+       }
        return s.placeholders
 }
 
+// hook to simulate broken connections
+var hookCommitBadConn func() bool
+
 func (tx *fakeTx) Commit() error {
        tx.c.currTx = nil
+       if hookCommitBadConn != nil && hookCommitBadConn() {
+               return driver.ErrBadConn
+       }
        return nil
 }
 
+// hook to simulate broken connections
+var hookRollbackBadConn func() bool
+
 func (tx *fakeTx) Rollback() error {
        tx.c.currTx = nil
+       if hookRollbackBadConn != nil && hookRollbackBadConn() {
+               return driver.ErrBadConn
+       }
        return nil
 }
 
index aaa4ea28be4527d956e58c08a9d103c2ac7ac42a..d8e7cb77af396e0d735ee766410adb91591b887c 100644 (file)
@@ -21,13 +21,17 @@ import (
        "sort"
        "sync"
        "sync/atomic"
+       "time"
 )
 
 var (
-       driversMu sync.Mutex
+       driversMu sync.RWMutex
        drivers   = make(map[string]driver.Driver)
 )
 
+// nowFunc returns the current time; it's overridden in tests.
+var nowFunc = time.Now
+
 // Register makes a database driver available by the provided name.
 // If Register is called twice with the same name or if driver is nil,
 // it panics.
@@ -52,8 +56,8 @@ func unregisterAllDrivers() {
 
 // Drivers returns a sorted list of the names of the registered drivers.
 func Drivers() []string {
-       driversMu.Lock()
-       defer driversMu.Unlock()
+       driversMu.RLock()
+       defer driversMu.RUnlock()
        var list []string
        for name := range drivers {
                list = append(list, name)
@@ -185,8 +189,7 @@ func (n NullBool) Value() (driver.Value, error) {
 type Scanner interface {
        // Scan assigns a value from a database driver.
        //
-       // The src value will be of one of the following restricted
-       // set of types:
+       // The src value will be of one of the following types:
        //
        //    int64
        //    float64
@@ -229,19 +232,20 @@ type DB struct {
        mu           sync.Mutex // protects following fields
        freeConn     []*driverConn
        connRequests []chan connRequest
-       numOpen      int
-       pendingOpens int
+       numOpen      int // number of opened and pending open connections
        // Used to signal the need for new connections
        // a goroutine running connectionOpener() reads on this chan and
        // maybeOpenNewConnections sends on the chan (one send per needed connection)
        // It is closed during db.Close(). The close tells the connectionOpener
        // goroutine to exit.
-       openerCh chan struct{}
-       closed   bool
-       dep      map[finalCloser]depSet
-       lastPut  map[*driverConn]string // stacktrace of last conn's put; debug only
-       maxIdle  int                    // zero means defaultMaxIdleConns; negative means 0
-       maxOpen  int                    // <= 0 means unlimited
+       openerCh    chan struct{}
+       closed      bool
+       dep         map[finalCloser]depSet
+       lastPut     map[*driverConn]string // stacktrace of last conn's put; debug only
+       maxIdle     int                    // zero means defaultMaxIdleConns; negative means 0
+       maxOpen     int                    // <= 0 means unlimited
+       maxLifetime time.Duration          // maximum amount of time a connection may be reused
+       cleanerCh   chan struct{}
 }
 
 // connReuseStrategy determines how (*DB).conn returns database connections.
@@ -261,7 +265,8 @@ const (
 // interfaces returned via that Conn, such as calls on Tx, Stmt,
 // Result, Rows)
 type driverConn struct {
-       db *DB
+       db        *DB
+       createdAt time.Time
 
        sync.Mutex  // guards following
        ci          driver.Conn
@@ -285,6 +290,13 @@ func (dc *driverConn) removeOpenStmt(si driver.Stmt) {
        delete(dc.openStmt, si)
 }
 
+func (dc *driverConn) expired(timeout time.Duration) bool {
+       if timeout <= 0 {
+               return false
+       }
+       return dc.createdAt.Add(timeout).Before(nowFunc())
+}
+
 func (dc *driverConn) prepareLocked(query string) (driver.Stmt, error) {
        si, err := dc.ci.Prepare(query)
        if err == nil {
@@ -441,7 +453,7 @@ func (db *DB) removeDepLocked(x finalCloser, dep interface{}) func() error {
        }
 }
 
-// This is the size of the connectionOpener request chan (dn.openerCh).
+// This is the size of the connectionOpener request chan (DB.openerCh).
 // 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
@@ -466,9 +478,9 @@ var connectionRequestQueueSize = 1000000
 // function should be called just once. It is rarely necessary to
 // close a DB.
 func Open(driverName, dataSourceName string) (*DB, error) {
-       driversMu.Lock()
+       driversMu.RLock()
        driveri, ok := drivers[driverName]
-       driversMu.Unlock()
+       driversMu.RUnlock()
        if !ok {
                return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
        }
@@ -507,6 +519,9 @@ func (db *DB) Close() error {
                return nil
        }
        close(db.openerCh)
+       if db.cleanerCh != nil {
+               close(db.cleanerCh)
+       }
        var err error
        fns := make([]func() error, 0, len(db.freeConn))
        for _, dc := range db.freeConn {
@@ -595,6 +610,84 @@ func (db *DB) SetMaxOpenConns(n int) {
        }
 }
 
+// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
+//
+// Expired connections may be closed lazily before reuse.
+//
+// If d <= 0, connections are reused forever.
+func (db *DB) SetConnMaxLifetime(d time.Duration) {
+       if d < 0 {
+               d = 0
+       }
+       db.mu.Lock()
+       // wake cleaner up when lifetime is shortened.
+       if d > 0 && d < db.maxLifetime && db.cleanerCh != nil {
+               select {
+               case db.cleanerCh <- struct{}{}:
+               default:
+               }
+       }
+       db.maxLifetime = d
+       db.startCleanerLocked()
+       db.mu.Unlock()
+}
+
+// startCleanerLocked starts connectionCleaner if needed.
+func (db *DB) startCleanerLocked() {
+       if db.maxLifetime > 0 && db.numOpen > 0 && db.cleanerCh == nil {
+               db.cleanerCh = make(chan struct{}, 1)
+               go db.connectionCleaner(db.maxLifetime)
+       }
+}
+
+func (db *DB) connectionCleaner(d time.Duration) {
+       const minInterval = time.Second
+
+       if d < minInterval {
+               d = minInterval
+       }
+       t := time.NewTimer(d)
+
+       for {
+               select {
+               case <-t.C:
+               case <-db.cleanerCh: // maxLifetime was changed or db was closed.
+               }
+
+               db.mu.Lock()
+               d = db.maxLifetime
+               if db.closed || db.numOpen == 0 || d <= 0 {
+                       db.cleanerCh = nil
+                       db.mu.Unlock()
+                       return
+               }
+
+               expiredSince := nowFunc().Add(-d)
+               var closing []*driverConn
+               for i := 0; i < len(db.freeConn); i++ {
+                       c := db.freeConn[i]
+                       if c.createdAt.Before(expiredSince) {
+                               closing = append(closing, c)
+                               last := len(db.freeConn) - 1
+                               db.freeConn[i] = db.freeConn[last]
+                               db.freeConn[last] = nil
+                               db.freeConn = db.freeConn[:last]
+                               i--
+                       }
+               }
+               db.mu.Unlock()
+
+               for _, c := range closing {
+                       c.Close()
+               }
+
+               if d < minInterval {
+                       d = minInterval
+               }
+               t.Reset(d)
+       }
+}
+
 // DBStats contains database statistics.
 type DBStats struct {
        // OpenConnections is the number of open connections to the database.
@@ -615,15 +708,15 @@ func (db *DB) Stats() DBStats {
 // If there are connRequests and the connection limit hasn't been reached,
 // then tell the connectionOpener to open new connections.
 func (db *DB) maybeOpenNewConnections() {
-       numRequests := len(db.connRequests) - db.pendingOpens
+       numRequests := len(db.connRequests)
        if db.maxOpen > 0 {
-               numCanOpen := db.maxOpen - (db.numOpen + db.pendingOpens)
+               numCanOpen := db.maxOpen - db.numOpen
                if numRequests > numCanOpen {
                        numRequests = numCanOpen
                }
        }
        for numRequests > 0 {
-               db.pendingOpens++
+               db.numOpen++ // optimistically
                numRequests--
                db.openerCh <- struct{}{}
        }
@@ -638,6 +731,9 @@ func (db *DB) connectionOpener() {
 
 // Open one new connection
 func (db *DB) openNewConnection() {
+       // maybeOpenNewConnctions has already executed db.numOpen++ before it sent
+       // on db.openerCh. This function must execute db.numOpen-- if the
+       // connection fails or is closed before returning.
        ci, err := db.driver.Open(db.dsn)
        db.mu.Lock()
        defer db.mu.Unlock()
@@ -645,21 +741,24 @@ func (db *DB) openNewConnection() {
                if err == nil {
                        ci.Close()
                }
+               db.numOpen--
                return
        }
-       db.pendingOpens--
        if err != nil {
+               db.numOpen--
                db.putConnDBLocked(nil, err)
+               db.maybeOpenNewConnections()
                return
        }
        dc := &driverConn{
-               db: db,
-               ci: ci,
+               db:        db,
+               createdAt: nowFunc(),
+               ci:        ci,
        }
        if db.putConnDBLocked(dc, err) {
                db.addDepLocked(dc, dc)
-               db.numOpen++
        } else {
+               db.numOpen--
                ci.Close()
        }
 }
@@ -681,6 +780,7 @@ func (db *DB) conn(strategy connReuseStrategy) (*driverConn, error) {
                db.mu.Unlock()
                return nil, errDBClosed
        }
+       lifetime := db.maxLifetime
 
        // Prefer a free connection, if possible.
        numFree := len(db.freeConn)
@@ -690,6 +790,10 @@ func (db *DB) conn(strategy connReuseStrategy) (*driverConn, error) {
                db.freeConn = db.freeConn[:numFree-1]
                conn.inUse = true
                db.mu.Unlock()
+               if conn.expired(lifetime) {
+                       conn.Close()
+                       return nil, driver.ErrBadConn
+               }
                return conn, nil
        }
 
@@ -701,7 +805,14 @@ func (db *DB) conn(strategy connReuseStrategy) (*driverConn, error) {
                req := make(chan connRequest, 1)
                db.connRequests = append(db.connRequests, req)
                db.mu.Unlock()
-               ret := <-req
+               ret, ok := <-req
+               if !ok {
+                       return nil, errDBClosed
+               }
+               if ret.err == nil && ret.conn.expired(lifetime) {
+                       ret.conn.Close()
+                       return nil, driver.ErrBadConn
+               }
                return ret.conn, ret.err
        }
 
@@ -711,13 +822,15 @@ func (db *DB) conn(strategy connReuseStrategy) (*driverConn, error) {
        if err != nil {
                db.mu.Lock()
                db.numOpen-- // correct for earlier optimism
+               db.maybeOpenNewConnections()
                db.mu.Unlock()
                return nil, err
        }
        db.mu.Lock()
        dc := &driverConn{
-               db: db,
-               ci: ci,
+               db:        db,
+               createdAt: nowFunc(),
+               ci:        ci,
        }
        db.addDepLocked(dc, dc)
        dc.inUse = true
@@ -827,6 +940,7 @@ func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
                return true
        } else if err == nil && !db.closed && db.maxIdleConnsLocked() > len(db.freeConn) {
                db.freeConn = append(db.freeConn, dc)
+               db.startCleanerLocked()
                return true
        }
        return false
@@ -1022,7 +1136,7 @@ func (db *DB) queryConn(dc *driverConn, releaseConn func(error), query string, a
 }
 
 // QueryRow executes a query that is expected to return at most one row.
-// QueryRow always return a non-nil value. Errors are deferred until
+// QueryRow always returns a non-nil value. Errors are deferred until
 // Row's Scan method is called.
 func (db *DB) QueryRow(query string, args ...interface{}) *Row {
        rows, err := db.Query(query, args...)
@@ -1103,12 +1217,12 @@ type Tx struct {
 
 var ErrTxDone = errors.New("sql: Transaction has already been committed or rolled back")
 
-func (tx *Tx) close() {
+func (tx *Tx) close(err error) {
        if tx.done {
                panic("double close") // internal error
        }
        tx.done = true
-       tx.db.putConn(tx.dc, nil)
+       tx.db.putConn(tx.dc, err)
        tx.dc = nil
        tx.txi = nil
 }
@@ -1134,13 +1248,13 @@ func (tx *Tx) Commit() error {
        if tx.done {
                return ErrTxDone
        }
-       defer tx.close()
        tx.dc.Lock()
        err := tx.txi.Commit()
        tx.dc.Unlock()
        if err != driver.ErrBadConn {
                tx.closePrepared()
        }
+       tx.close(err)
        return err
 }
 
@@ -1149,13 +1263,13 @@ func (tx *Tx) Rollback() error {
        if tx.done {
                return ErrTxDone
        }
-       defer tx.close()
        tx.dc.Lock()
        err := tx.txi.Rollback()
        tx.dc.Unlock()
        if err != driver.ErrBadConn {
                tx.closePrepared()
        }
+       tx.close(err)
        return err
 }
 
@@ -1296,7 +1410,7 @@ func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
 }
 
 // QueryRow executes a query that is expected to return at most one row.
-// QueryRow always return a non-nil value. Errors are deferred until
+// QueryRow always returns a non-nil value. Errors are deferred until
 // Row's Scan method is called.
 func (tx *Tx) QueryRow(query string, args ...interface{}) *Row {
        rows, err := tx.Query(query, args...)
@@ -1362,10 +1476,14 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
        return nil, driver.ErrBadConn
 }
 
-func resultFromStatement(ds driverStmt, args ...interface{}) (Result, error) {
+func driverNumInput(ds driverStmt) int {
        ds.Lock()
-       want := ds.si.NumInput()
-       ds.Unlock()
+       defer ds.Unlock() // in case NumInput panics
+       return ds.si.NumInput()
+}
+
+func resultFromStatement(ds driverStmt, args ...interface{}) (Result, error) {
+       want := driverNumInput(ds)
 
        // -1 means the driver doesn't know how to count the number of
        // placeholders, so we won't sanity check input here and instead let the
@@ -1380,8 +1498,8 @@ func resultFromStatement(ds driverStmt, args ...interface{}) (Result, error) {
        }
 
        ds.Lock()
+       defer ds.Unlock()
        resi, err := ds.si.Exec(dargs)
-       ds.Unlock()
        if err != nil {
                return nil, err
        }
@@ -1576,9 +1694,9 @@ func (s *Stmt) Close() error {
        s.closed = true
 
        if s.tx != nil {
-               s.txsi.Close()
+               err := s.txsi.Close()
                s.mu.Unlock()
-               return nil
+               return err
        }
        s.mu.Unlock()
 
@@ -1667,17 +1785,56 @@ func (rs *Rows) Columns() ([]string, error) {
 }
 
 // Scan copies the columns in the current row into the values pointed
-// at by dest.
+// at by dest. The number of values in dest must be the same as the
+// number of columns in Rows.
+//
+// Scan converts columns read from the database into the following
+// common Go types and special types provided by the sql package:
+//
+//    *string
+//    *[]byte
+//    *int, *int8, *int16, *int32, *int64
+//    *uint, *uint8, *uint16, *uint32, *uint64
+//    *bool
+//    *float32, *float64
+//    *interface{}
+//    *RawBytes
+//    any type implementing Scanner (see Scanner docs)
+//
+// In the most simple case, if the type of the value from the source
+// column is an integer, bool or string type T and dest is of type *T,
+// Scan simply assigns the value through the pointer.
 //
-// If an argument has type *[]byte, Scan saves in that argument a copy
-// of the corresponding data. The copy is owned by the caller and can
-// be modified and held indefinitely. The copy can be avoided by using
-// an argument of type *RawBytes instead; see the documentation for
-// RawBytes for restrictions on its use.
+// Scan also converts between string and numeric types, as long as no
+// information would be lost. While Scan stringifies all numbers
+// scanned from numeric database columns into *string, scans into
+// numeric types are checked for overflow. For example, a float64 with
+// value 300 or a string with value "300" can scan into a uint16, but
+// not into a uint8, though float64(255) or "255" can scan into a
+// uint8. One exception is that scans of some float64 numbers to
+// strings may lose information when stringifying. In general, scan
+// floating point columns into *float64.
+//
+// If a dest argument has type *[]byte, Scan saves in that argument a
+// copy of the corresponding data. The copy is owned by the caller and
+// can be modified and held indefinitely. The copy can be avoided by
+// using an argument of type *RawBytes instead; see the documentation
+// for RawBytes for restrictions on its use.
 //
 // If an argument has type *interface{}, Scan copies the value
-// provided by the underlying driver without conversion. If the value
-// is of type []byte, a copy is made and the caller owns the result.
+// provided by the underlying driver without conversion. When scanning
+// from a source value of type []byte to *interface{}, a copy of the
+// slice is made and the caller owns the result.
+//
+// Source values of type time.Time may be scanned into values of type
+// *time.Time, *interface{}, *string, or *[]byte. When converting to
+// the latter two, time.Format3339Nano is used.
+//
+// Source values of type bool may be scanned into types *bool,
+// *interface{}, *string, *[]byte, or *RawBytes.
+//
+// For scanning into *bool, the source may be true, false, 1, 0, or
+// string inputs parseable by strconv.ParseBool.
 func (rs *Rows) Scan(dest ...interface{}) error {
        if rs.closed {
                return errors.New("sql: Rows are closed")
@@ -1726,8 +1883,9 @@ type Row struct {
 }
 
 // Scan copies the columns from the matched row into the values
-// pointed at by dest.  If more than one row matches the query,
-// Scan uses the first row and discards the rest.  If no row matches
+// pointed at by dest. See the documentation on Rows.Scan for details.
+// If more than one row matches the query,
+// Scan uses the first row and discards the rest. If no row matches
 // the query, Scan returns ErrNoRows.
 func (r *Row) Scan(dest ...interface{}) error {
        if r.err != nil {
@@ -1812,6 +1970,6 @@ func stack() string {
 // withLock runs while holding lk.
 func withLock(lk sync.Locker, fn func()) {
        lk.Lock()
+       defer lk.Unlock() // in case fn panics
        fn()
-       lk.Unlock()
 }
index 432a641b85549632dba855b4500a7bf32a209ae4..8ec70d99b02c5374b5e1de8177bc59096f3ff0e5 100644 (file)
@@ -68,6 +68,46 @@ func newTestDB(t testing.TB, name string) *DB {
        return db
 }
 
+func TestDriverPanic(t *testing.T) {
+       // Test that if driver panics, database/sql does not deadlock.
+       db, err := Open("test", fakeDBName)
+       if err != nil {
+               t.Fatalf("Open: %v", err)
+       }
+       expectPanic := func(name string, f func()) {
+               defer func() {
+                       err := recover()
+                       if err == nil {
+                               t.Fatalf("%s did not panic", name)
+                       }
+               }()
+               f()
+       }
+
+       expectPanic("Exec Exec", func() { db.Exec("PANIC|Exec|WIPE") })
+       exec(t, db, "WIPE") // check not deadlocked
+       expectPanic("Exec NumInput", func() { db.Exec("PANIC|NumInput|WIPE") })
+       exec(t, db, "WIPE") // check not deadlocked
+       expectPanic("Exec Close", func() { db.Exec("PANIC|Close|WIPE") })
+       exec(t, db, "WIPE")             // check not deadlocked
+       exec(t, db, "PANIC|Query|WIPE") // should run successfully: Exec does not call Query
+       exec(t, db, "WIPE")             // check not deadlocked
+
+       exec(t, db, "CREATE|people|name=string,age=int32,photo=blob,dead=bool,bdate=datetime")
+
+       expectPanic("Query Query", func() { db.Query("PANIC|Query|SELECT|people|age,name|") })
+       expectPanic("Query NumInput", func() { db.Query("PANIC|NumInput|SELECT|people|age,name|") })
+       expectPanic("Query Close", func() {
+               rows, err := db.Query("PANIC|Close|SELECT|people|age,name|")
+               if err != nil {
+                       t.Fatal(err)
+               }
+               rows.Close()
+       })
+       db.Query("PANIC|Exec|SELECT|people|age,name|") // should run successfully: Query does not call Exec
+       exec(t, db, "WIPE")                            // check not deadlocked
+}
+
 func exec(t testing.TB, db *DB, query string, args ...interface{}) {
        _, err := db.Exec(query, args...)
        if err != nil {
@@ -142,6 +182,20 @@ func (db *DB) numFreeConns() int {
        return len(db.freeConn)
 }
 
+// clearAllConns closes all connections in db.
+func (db *DB) clearAllConns(t *testing.T) {
+       db.SetMaxIdleConns(0)
+
+       if g, w := db.numFreeConns(), 0; g != w {
+               t.Errorf("free conns = %d; want %d", g, w)
+       }
+
+       if n := db.numDepsPollUntil(0, time.Second); n > 0 {
+               t.Errorf("number of dependencies = %d; expected 0", n)
+               db.dumpDeps(t)
+       }
+}
+
 func (db *DB) dumpDeps(t *testing.T) {
        for fc := range db.dep {
                db.dumpDep(t, 0, fc, map[finalCloser]bool{})
@@ -356,6 +410,44 @@ func TestStatementQueryRow(t *testing.T) {
        }
 }
 
+type stubDriverStmt struct {
+       err error
+}
+
+func (s stubDriverStmt) Close() error {
+       return s.err
+}
+
+func (s stubDriverStmt) NumInput() int {
+       return -1
+}
+
+func (s stubDriverStmt) Exec(args []driver.Value) (driver.Result, error) {
+       return nil, nil
+}
+
+func (s stubDriverStmt) Query(args []driver.Value) (driver.Rows, error) {
+       return nil, nil
+}
+
+// golang.org/issue/12798
+func TestStatementClose(t *testing.T) {
+       want := errors.New("STMT ERROR")
+
+       tests := []struct {
+               stmt *Stmt
+               msg  string
+       }{
+               {&Stmt{stickyErr: want}, "stickyErr not propagated"},
+               {&Stmt{tx: &Tx{}, txsi: &driverStmt{&sync.Mutex{}, stubDriverStmt{want}}}, "driverStmt.Close() error not propagated"},
+       }
+       for _, test := range tests {
+               if err := test.stmt.Close(); err != want {
+                       t.Errorf("%s. Got stmt.Close() = %v, want = %v", test.msg, err, want)
+               }
+       }
+}
+
 // golang.org/issue/3734
 func TestStatementQueryRowConcurrent(t *testing.T) {
        db := newTestDB(t, "people")
@@ -953,16 +1045,7 @@ func TestMaxOpenConns(t *testing.T) {
 
        // Force the number of open connections to 0 so we can get an accurate
        // count for the test
-       db.SetMaxIdleConns(0)
-
-       if g, w := db.numFreeConns(), 0; g != w {
-               t.Errorf("free conns = %d; want %d", g, w)
-       }
-
-       if n := db.numDepsPollUntil(0, time.Second); n > 0 {
-               t.Errorf("number of dependencies = %d; expected 0", n)
-               db.dumpDeps(t)
-       }
+       db.clearAllConns(t)
 
        driver.mu.Lock()
        opens0 := driver.openCount
@@ -1058,16 +1141,7 @@ func TestMaxOpenConns(t *testing.T) {
                db.dumpDeps(t)
        }
 
-       db.SetMaxIdleConns(0)
-
-       if g, w := db.numFreeConns(), 0; g != w {
-               t.Errorf("free conns = %d; want %d", g, w)
-       }
-
-       if n := db.numDepsPollUntil(0, time.Second); n > 0 {
-               t.Errorf("number of dependencies = %d; expected 0", n)
-               db.dumpDeps(t)
-       }
+       db.clearAllConns(t)
 }
 
 // Issue 9453: tests that SetMaxOpenConns can be lowered at runtime
@@ -1121,6 +1195,67 @@ func TestMaxOpenConnsOnBusy(t *testing.T) {
        }
 }
 
+// Issue 10886: tests that all connection attempts return when more than
+// DB.maxOpen connections are in flight and the first DB.maxOpen fail.
+func TestPendingConnsAfterErr(t *testing.T) {
+       const (
+               maxOpen = 2
+               tryOpen = maxOpen*2 + 2
+       )
+
+       db := newTestDB(t, "people")
+       defer closeDB(t, db)
+       defer func() {
+               for k, v := range db.lastPut {
+                       t.Logf("%p: %v", k, v)
+               }
+       }()
+
+       db.SetMaxOpenConns(maxOpen)
+       db.SetMaxIdleConns(0)
+
+       errOffline := errors.New("db offline")
+       defer func() { setHookOpenErr(nil) }()
+
+       errs := make(chan error, tryOpen)
+
+       unblock := make(chan struct{})
+       setHookOpenErr(func() error {
+               <-unblock // block until all connections are in flight
+               return errOffline
+       })
+
+       var opening sync.WaitGroup
+       opening.Add(tryOpen)
+       for i := 0; i < tryOpen; i++ {
+               go func() {
+                       opening.Done() // signal one connection is in flight
+                       _, err := db.Exec("INSERT|people|name=Julia,age=19")
+                       errs <- err
+               }()
+       }
+
+       opening.Wait()                    // wait for all workers to begin running
+       time.Sleep(10 * time.Millisecond) // make extra sure all workers are blocked
+       close(unblock)                    // let all workers proceed
+
+       const timeout = 100 * time.Millisecond
+       to := time.NewTimer(timeout)
+       defer to.Stop()
+
+       // check that all connections fail without deadlock
+       for i := 0; i < tryOpen; i++ {
+               select {
+               case err := <-errs:
+                       if got, want := err, errOffline; got != want {
+                               t.Errorf("unexpected err: got %v, want %v", got, want)
+                       }
+               case <-to.C:
+                       t.Fatalf("orphaned connection request(s), still waiting after %v", timeout)
+               }
+       }
+}
+
 func TestSingleOpenConn(t *testing.T) {
        db := newTestDB(t, "people")
        defer closeDB(t, db)
@@ -1164,6 +1299,90 @@ func TestStats(t *testing.T) {
        }
 }
 
+func TestConnMaxLifetime(t *testing.T) {
+       t0 := time.Unix(1000000, 0)
+       offset := time.Duration(0)
+
+       nowFunc = func() time.Time { return t0.Add(offset) }
+       defer func() { nowFunc = time.Now }()
+
+       db := newTestDB(t, "magicquery")
+       defer closeDB(t, db)
+
+       driver := db.driver.(*fakeDriver)
+
+       // Force the number of open connections to 0 so we can get an accurate
+       // count for the test
+       db.clearAllConns(t)
+
+       driver.mu.Lock()
+       opens0 := driver.openCount
+       closes0 := driver.closeCount
+       driver.mu.Unlock()
+
+       db.SetMaxIdleConns(10)
+       db.SetMaxOpenConns(10)
+
+       tx, err := db.Begin()
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       offset = time.Second
+       tx2, err := db.Begin()
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       tx.Commit()
+       tx2.Commit()
+
+       driver.mu.Lock()
+       opens := driver.openCount - opens0
+       closes := driver.closeCount - closes0
+       driver.mu.Unlock()
+
+       if opens != 2 {
+               t.Errorf("opens = %d; want 2", opens)
+       }
+       if closes != 0 {
+               t.Errorf("closes = %d; want 0", closes)
+       }
+       if g, w := db.numFreeConns(), 2; g != w {
+               t.Errorf("free conns = %d; want %d", g, w)
+       }
+
+       // Expire first conn
+       offset = time.Second * 11
+       db.SetConnMaxLifetime(time.Second * 10)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       tx, err = db.Begin()
+       if err != nil {
+               t.Fatal(err)
+       }
+       tx2, err = db.Begin()
+       if err != nil {
+               t.Fatal(err)
+       }
+       tx.Commit()
+       tx2.Commit()
+
+       driver.mu.Lock()
+       opens = driver.openCount - opens0
+       closes = driver.closeCount - closes0
+       driver.mu.Unlock()
+
+       if opens != 3 {
+               t.Errorf("opens = %d; want 3", opens)
+       }
+       if closes != 1 {
+               t.Errorf("closes = %d; want 1", closes)
+       }
+}
+
 // golang.org/issue/5323
 func TestStmtCloseDeps(t *testing.T) {
        if testing.Short() {
@@ -1257,16 +1476,7 @@ func TestStmtCloseDeps(t *testing.T) {
                db.dumpDeps(t)
        }
 
-       db.SetMaxIdleConns(0)
-
-       if g, w := db.numFreeConns(), 0; g != w {
-               t.Errorf("free conns = %d; want %d", g, w)
-       }
-
-       if n := db.numDepsPollUntil(0, time.Second); n > 0 {
-               t.Errorf("number of dependencies = %d; expected 0", n)
-               db.dumpDeps(t)
-       }
+       db.clearAllConns(t)
 }
 
 // golang.org/issue/5046
@@ -1564,6 +1774,77 @@ func TestErrBadConnReconnect(t *testing.T) {
        simulateBadConn("stmt.Query exec", &hookQueryBadConn, stmtQuery)
 }
 
+// golang.org/issue/11264
+func TestTxEndBadConn(t *testing.T) {
+       db := newTestDB(t, "foo")
+       defer closeDB(t, db)
+       db.SetMaxIdleConns(0)
+       exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
+       db.SetMaxIdleConns(1)
+
+       simulateBadConn := func(name string, hook *func() bool, op func() error) {
+               broken := false
+               numOpen := db.numOpen
+
+               *hook = func() bool {
+                       if !broken {
+                               broken = true
+                       }
+                       return broken
+               }
+
+               if err := op(); err != driver.ErrBadConn {
+                       t.Errorf(name+": %v", err)
+                       return
+               }
+
+               if !broken {
+                       t.Error(name + ": Failed to simulate broken connection")
+               }
+               *hook = nil
+
+               if numOpen != db.numOpen {
+                       t.Errorf(name+": leaked %d connection(s)!", db.numOpen-numOpen)
+               }
+       }
+
+       // db.Exec
+       dbExec := func(endTx func(tx *Tx) error) func() error {
+               return func() error {
+                       tx, err := db.Begin()
+                       if err != nil {
+                               return err
+                       }
+                       _, err = tx.Exec("INSERT|t1|name=?,age=?,dead=?", "Gordon", 3, true)
+                       if err != nil {
+                               return err
+                       }
+                       return endTx(tx)
+               }
+       }
+       simulateBadConn("db.Tx.Exec commit", &hookCommitBadConn, dbExec((*Tx).Commit))
+       simulateBadConn("db.Tx.Exec rollback", &hookRollbackBadConn, dbExec((*Tx).Rollback))
+
+       // db.Query
+       dbQuery := func(endTx func(tx *Tx) error) func() error {
+               return func() error {
+                       tx, err := db.Begin()
+                       if err != nil {
+                               return err
+                       }
+                       rows, err := tx.Query("SELECT|t1|age,name|")
+                       if err == nil {
+                               err = rows.Close()
+                       } else {
+                               return err
+                       }
+                       return endTx(tx)
+               }
+       }
+       simulateBadConn("db.Tx.Query commit", &hookCommitBadConn, dbQuery((*Tx).Commit))
+       simulateBadConn("db.Tx.Query rollback", &hookRollbackBadConn, dbQuery((*Tx).Rollback))
+}
+
 type concurrentTest interface {
        init(t testing.TB, db *DB)
        finish(t testing.TB)
index 0b1206b9f3daf08388f77fbd433d08a07b3e5a6c..d57d9f71c4350ea25a78ba7874a41fb469c4d980 100644 (file)
@@ -4,14 +4,13 @@ package dwarf
 
 import "fmt"
 
-const _Class_name = "ClassAddressClassBlockClassConstantClassExprLocClassFlagClassLinePtrClassLocListPtrClassMacPtrClassRangeListPtrClassReferenceClassReferenceSigClassStringClassReferenceAltClassStringAlt"
+const _Class_name = "ClassUnknownClassAddressClassBlockClassConstantClassExprLocClassFlagClassLinePtrClassLocListPtrClassMacPtrClassRangeListPtrClassReferenceClassReferenceSigClassStringClassReferenceAltClassStringAlt"
 
-var _Class_index = [...]uint8{0, 12, 22, 35, 47, 56, 68, 83, 94, 111, 125, 142, 153, 170, 184}
+var _Class_index = [...]uint8{0, 12, 24, 34, 47, 59, 68, 80, 95, 106, 123, 137, 154, 165, 182, 196}
 
 func (i Class) String() string {
-       i -= 1
        if i < 0 || i+1 >= Class(len(_Class_index)) {
-               return fmt.Sprintf("Class(%d)", i+1)
+               return fmt.Sprintf("Class(%d)", i)
        }
        return _Class_name[_Class_index[i]:_Class_index[i+1]]
 }
index d607e5b4a38e498d04cb1d1208ee4a04d74baffd..5ca86679fa5116a3cd5122921b539fc209714f12 100644 (file)
@@ -193,8 +193,7 @@ func formToClass(form format, attr Attr, vers int, b *buf) Class {
                if class, ok := attrPtrClass[attr]; ok {
                        return class
                }
-               b.error("cannot determine class of unknown attribute with formSecOffset")
-               return 0
+               return ClassUnknown
 
        case formExprloc:
                return ClassExprLoc
@@ -235,6 +234,9 @@ type Entry struct {
 //    loclistptr        int64          ClassLocListPtr
 //    macptr            int64          ClassMacPtr
 //    rangelistptr      int64          ClassRangeListPtr
+//
+// For unrecognized or vendor-defined attributes, Class may be
+// ClassUnknown.
 type Field struct {
        Attr  Attr
        Val   interface{}
@@ -258,9 +260,12 @@ type Field struct {
 type Class int
 
 const (
+       // ClassUnknown represents values of unknown DWARF class.
+       ClassUnknown Class = iota
+
        // ClassAddress represents values of type uint64 that are
        // addresses on the target machine.
-       ClassAddress Class = 1 + iota
+       ClassAddress
 
        // ClassBlock represents values of type []byte whose
        // interpretation depends on the attribute.
diff --git a/libgo/go/debug/dwarf/entry_test.go b/libgo/go/debug/dwarf/entry_test.go
new file mode 100644 (file)
index 0000000..8bd2d2a
--- /dev/null
@@ -0,0 +1,36 @@
+// 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 dwarf_test
+
+import (
+       . "debug/dwarf"
+       "testing"
+)
+
+func TestSplit(t *testing.T) {
+       // debug/dwarf doesn't (currently) support split DWARF, but
+       // the attributes that pointed to the split DWARF used to
+       // cause loading the DWARF data to fail entirely (issue
+       // #12592). Test that we can at least read the DWARF data.
+       d := elfData(t, "testdata/split.elf")
+       r := d.Reader()
+       e, err := r.Next()
+       if err != nil {
+               t.Fatal(err)
+       }
+       if e.Tag != TagCompileUnit {
+               t.Fatalf("bad tag: have %s, want %s", e.Tag, TagCompileUnit)
+       }
+       // Check that we were able to parse the unknown section offset
+       // field, even if we can't figure out its DWARF class.
+       const AttrGNUAddrBase Attr = 0x2133
+       f := e.AttrField(AttrGNUAddrBase)
+       if _, ok := f.Val.(int64); !ok {
+               t.Fatalf("bad attribute value type: have %T, want int64", f.Val)
+       }
+       if f.Class != ClassUnknown {
+               t.Fatalf("bad class: have %s, want %s", f.Class, ClassUnknown)
+       }
+}
diff --git a/libgo/go/debug/dwarf/testdata/cycle.c b/libgo/go/debug/dwarf/testdata/cycle.c
new file mode 100644 (file)
index 0000000..a0b53df
--- /dev/null
@@ -0,0 +1,7 @@
+typedef struct aaa *AAA;
+typedef AAA BBB;
+struct aaa { BBB val; };
+
+AAA x(void) {
+    return (AAA)0;
+}
diff --git a/libgo/go/debug/dwarf/testdata/cycle.elf b/libgo/go/debug/dwarf/testdata/cycle.elf
new file mode 100644 (file)
index 0000000..e0b66ca
Binary files /dev/null and b/libgo/go/debug/dwarf/testdata/cycle.elf differ
diff --git a/libgo/go/debug/dwarf/testdata/split.c b/libgo/go/debug/dwarf/testdata/split.c
new file mode 100644 (file)
index 0000000..0ef3427
--- /dev/null
@@ -0,0 +1,5 @@
+// gcc -gsplit-dwarf split.c -o split.elf
+
+int main() 
+{
+}
diff --git a/libgo/go/debug/dwarf/testdata/split.elf b/libgo/go/debug/dwarf/testdata/split.elf
new file mode 100644 (file)
index 0000000..99ee2c2
Binary files /dev/null and b/libgo/go/debug/dwarf/testdata/split.elf differ
index a5daa1d0bb18e6e48b640ef5c4e87568a5f1709c..c76a472d78c067d8d971709d541b14e7a2e63181 100644 (file)
@@ -275,12 +275,14 @@ type typeReader interface {
 
 // Type reads the type at off in the DWARF ``info'' section.
 func (d *Data) Type(off Offset) (Type, error) {
-       return d.readType("info", d.Reader(), off, d.typeCache)
+       return d.readType("info", d.Reader(), off, d.typeCache, nil)
 }
 
-// readType reads a type from r at off of name using and updating a
-// type cache.
-func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type) (Type, error) {
+// readType reads a type from r at off of name. It adds types to the
+// type cache, appends new typedef types to typedefs, and computes the
+// sizes of types. Callers should pass nil for typedefs; this is used
+// for internal recursion.
+func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type, typedefs *[]*TypedefType) (Type, error) {
        if t, ok := typeCache[off]; ok {
                return t, nil
        }
@@ -294,9 +296,24 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
                return nil, DecodeError{name, off, "no type at offset"}
        }
 
+       // If this is the root of the recursion, prepare to resolve
+       // typedef sizes once the recursion is done. This must be done
+       // after the type graph is constructed because it may need to
+       // resolve cycles in a different order than readType
+       // encounters them.
+       if typedefs == nil {
+               var typedefList []*TypedefType
+               defer func() {
+                       for _, t := range typedefList {
+                               t.Common().ByteSize = t.Type.Size()
+                       }
+               }()
+               typedefs = &typedefList
+       }
+
        // Parse type from Entry.
        // Must always set typeCache[off] before calling
-       // d.Type recursively, to handle circular types correctly.
+       // d.readType recursively, to handle circular types correctly.
        var typ Type
 
        nextDepth := 0
@@ -345,7 +362,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
                var t Type
                switch toff := tval.(type) {
                case Offset:
-                       if t, err = d.readType(name, r.clone(), toff, typeCache); err != nil {
+                       if t, err = d.readType(name, r.clone(), toff, typeCache, typedefs); err != nil {
                                return nil
                        }
                case uint64:
@@ -674,7 +691,10 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
                        b = -1
                        switch t := typ.(type) {
                        case *TypedefType:
-                               b = t.Type.Size()
+                               // Record that we need to resolve this
+                               // type's size once the type graph is
+                               // constructed.
+                               *typedefs = append(*typedefs, t)
                        case *PtrType:
                                b = int64(addressSize)
                        }
index 2cb85e74bb23a76a81817f6bdafd0b327a838c43..ad6308deba0323e7b452492fe9c4651066a3c5f4 100644 (file)
@@ -120,3 +120,37 @@ func testTypedefs(t *testing.T, d *Data, kind string) {
                }
        }
 }
+
+func TestTypedefCycle(t *testing.T) {
+       // See issue #13039: reading a typedef cycle starting from a
+       // different place than the size needed to be computed from
+       // used to crash.
+       //
+       // cycle.elf built with GCC 4.8.4:
+       //    gcc -g -c -o cycle.elf cycle.c
+       d := elfData(t, "testdata/cycle.elf")
+       r := d.Reader()
+       offsets := []Offset{}
+       for {
+               e, err := r.Next()
+               if err != nil {
+                       t.Fatal("r.Next:", err)
+               }
+               if e == nil {
+                       break
+               }
+               switch e.Tag {
+               case TagBaseType, TagTypedef, TagPointerType, TagStructType:
+                       offsets = append(offsets, e.Offset)
+               }
+       }
+
+       // Parse each type with a fresh type cache.
+       for _, offset := range offsets {
+               d := elfData(t, "testdata/cycle.elf")
+               _, err := d.Type(offset)
+               if err != nil {
+                       t.Fatalf("d.Type(0x%x): %s", offset, err)
+               }
+       }
+}
index 9cfb4a8b256d312da316f6132d4684d3ca849e35..0f4e07ebf7c8c35482837aaaaa2ac8911be40996 100644 (file)
@@ -101,7 +101,7 @@ func (d *Data) sigToType(sig uint64) (Type, error) {
 
        b := makeBuf(d, tu, tu.name, tu.off, tu.data)
        r := &typeUnitReader{d: d, tu: tu, b: b}
-       t, err := d.readType(tu.name, r, Offset(tu.toff), make(map[Offset]Type))
+       t, err := d.readType(tu.name, r, Offset(tu.toff), make(map[Offset]Type), nil)
        if err != nil {
                return nil, err
        }
index c97ccaa4c1c3cd67401ad65237cfb5e7964566cb..6086b54b9f29cd606776425a9721204a2640b26e 100644 (file)
@@ -411,6 +411,7 @@ const (
        SHF_OS_NONCONFORMING SectionFlag = 0x100      /* OS-specific processing required. */
        SHF_GROUP            SectionFlag = 0x200      /* Member of section group. */
        SHF_TLS              SectionFlag = 0x400      /* Section contains TLS data. */
+       SHF_COMPRESSED       SectionFlag = 0x800      /* Section is compressed. */
        SHF_MASKOS           SectionFlag = 0x0ff00000 /* OS-specific semantics. */
        SHF_MASKPROC         SectionFlag = 0xf0000000 /* Processor-specific semantics. */
 )
@@ -426,11 +427,34 @@ var shfStrings = []intName{
        {0x100, "SHF_OS_NONCONFORMING"},
        {0x200, "SHF_GROUP"},
        {0x400, "SHF_TLS"},
+       {0x800, "SHF_COMPRESSED"},
 }
 
 func (i SectionFlag) String() string   { return flagName(uint32(i), shfStrings, false) }
 func (i SectionFlag) GoString() string { return flagName(uint32(i), shfStrings, true) }
 
+// Section compression type.
+type CompressionType int
+
+const (
+       COMPRESS_ZLIB   CompressionType = 1          /* ZLIB compression. */
+       COMPRESS_LOOS   CompressionType = 0x60000000 /* First OS-specific. */
+       COMPRESS_HIOS   CompressionType = 0x6fffffff /* Last OS-specific. */
+       COMPRESS_LOPROC CompressionType = 0x70000000 /* First processor-specific type. */
+       COMPRESS_HIPROC CompressionType = 0x7fffffff /* Last processor-specific type. */
+)
+
+var compressionStrings = []intName{
+       {0, "COMPRESS_ZLIB"},
+       {0x60000000, "COMPRESS_LOOS"},
+       {0x6fffffff, "COMPRESS_HIOS"},
+       {0x70000000, "COMPRESS_LOPROC"},
+       {0x7fffffff, "COMPRESS_HIPROC"},
+}
+
+func (i CompressionType) String() string   { return stringName(uint32(i), compressionStrings, false) }
+func (i CompressionType) GoString() string { return stringName(uint32(i), compressionStrings, true) }
+
 // Prog.Type
 type ProgType int
 
@@ -1246,6 +1270,115 @@ var r386Strings = []intName{
 func (i R_386) String() string   { return stringName(uint32(i), r386Strings, false) }
 func (i R_386) GoString() string { return stringName(uint32(i), r386Strings, true) }
 
+// Relocation types for MIPS.
+type R_MIPS int
+
+const (
+       R_MIPS_NONE          R_MIPS = 0
+       R_MIPS_16            R_MIPS = 1
+       R_MIPS_32            R_MIPS = 2
+       R_MIPS_REL32         R_MIPS = 3
+       R_MIPS_26            R_MIPS = 4
+       R_MIPS_HI16          R_MIPS = 5  /* high 16 bits of symbol value */
+       R_MIPS_LO16          R_MIPS = 6  /* low 16 bits of symbol value */
+       R_MIPS_GPREL16       R_MIPS = 7  /* GP-relative reference  */
+       R_MIPS_LITERAL       R_MIPS = 8  /* Reference to literal section  */
+       R_MIPS_GOT16         R_MIPS = 9  /* Reference to global offset table */
+       R_MIPS_PC16          R_MIPS = 10 /* 16 bit PC relative reference */
+       R_MIPS_CALL16        R_MIPS = 11 /* 16 bit call thru glbl offset tbl */
+       R_MIPS_GPREL32       R_MIPS = 12
+       R_MIPS_SHIFT5        R_MIPS = 16
+       R_MIPS_SHIFT6        R_MIPS = 17
+       R_MIPS_64            R_MIPS = 18
+       R_MIPS_GOT_DISP      R_MIPS = 19
+       R_MIPS_GOT_PAGE      R_MIPS = 20
+       R_MIPS_GOT_OFST      R_MIPS = 21
+       R_MIPS_GOT_HI16      R_MIPS = 22
+       R_MIPS_GOT_LO16      R_MIPS = 23
+       R_MIPS_SUB           R_MIPS = 24
+       R_MIPS_INSERT_A      R_MIPS = 25
+       R_MIPS_INSERT_B      R_MIPS = 26
+       R_MIPS_DELETE        R_MIPS = 27
+       R_MIPS_HIGHER        R_MIPS = 28
+       R_MIPS_HIGHEST       R_MIPS = 29
+       R_MIPS_CALL_HI16     R_MIPS = 30
+       R_MIPS_CALL_LO16     R_MIPS = 31
+       R_MIPS_SCN_DISP      R_MIPS = 32
+       R_MIPS_REL16         R_MIPS = 33
+       R_MIPS_ADD_IMMEDIATE R_MIPS = 34
+       R_MIPS_PJUMP         R_MIPS = 35
+       R_MIPS_RELGOT        R_MIPS = 36
+       R_MIPS_JALR          R_MIPS = 37
+
+       R_MIPS_TLS_DTPMOD32    R_MIPS = 38 /* Module number 32 bit */
+       R_MIPS_TLS_DTPREL32    R_MIPS = 39 /* Module-relative offset 32 bit */
+       R_MIPS_TLS_DTPMOD64    R_MIPS = 40 /* Module number 64 bit */
+       R_MIPS_TLS_DTPREL64    R_MIPS = 41 /* Module-relative offset 64 bit */
+       R_MIPS_TLS_GD          R_MIPS = 42 /* 16 bit GOT offset for GD */
+       R_MIPS_TLS_LDM         R_MIPS = 43 /* 16 bit GOT offset for LDM */
+       R_MIPS_TLS_DTPREL_HI16 R_MIPS = 44 /* Module-relative offset, high 16 bits */
+       R_MIPS_TLS_DTPREL_LO16 R_MIPS = 45 /* Module-relative offset, low 16 bits */
+       R_MIPS_TLS_GOTTPREL    R_MIPS = 46 /* 16 bit GOT offset for IE */
+       R_MIPS_TLS_TPREL32     R_MIPS = 47 /* TP-relative offset, 32 bit */
+       R_MIPS_TLS_TPREL64     R_MIPS = 48 /* TP-relative offset, 64 bit */
+       R_MIPS_TLS_TPREL_HI16  R_MIPS = 49 /* TP-relative offset, high 16 bits */
+       R_MIPS_TLS_TPREL_LO16  R_MIPS = 50 /* TP-relative offset, low 16 bits */
+)
+
+var rmipsStrings = []intName{
+       {0, "R_MIPS_NONE"},
+       {1, "R_MIPS_16"},
+       {2, "R_MIPS_32"},
+       {3, "R_MIPS_REL32"},
+       {4, "R_MIPS_26"},
+       {5, "R_MIPS_HI16"},
+       {6, "R_MIPS_LO16"},
+       {7, "R_MIPS_GPREL16"},
+       {8, "R_MIPS_LITERAL"},
+       {9, "R_MIPS_GOT16"},
+       {10, "R_MIPS_PC16"},
+       {11, "R_MIPS_CALL16"},
+       {12, "R_MIPS_GPREL32"},
+       {16, "R_MIPS_SHIFT5"},
+       {17, "R_MIPS_SHIFT6"},
+       {18, "R_MIPS_64"},
+       {19, "R_MIPS_GOT_DISP"},
+       {20, "R_MIPS_GOT_PAGE"},
+       {21, "R_MIPS_GOT_OFST"},
+       {22, "R_MIPS_GOT_HI16"},
+       {23, "R_MIPS_GOT_LO16"},
+       {24, "R_MIPS_SUB"},
+       {25, "R_MIPS_INSERT_A"},
+       {26, "R_MIPS_INSERT_B"},
+       {27, "R_MIPS_DELETE"},
+       {28, "R_MIPS_HIGHER"},
+       {29, "R_MIPS_HIGHEST"},
+       {30, "R_MIPS_CALL_HI16"},
+       {31, "R_MIPS_CALL_LO16"},
+       {32, "R_MIPS_SCN_DISP"},
+       {33, "R_MIPS_REL16"},
+       {34, "R_MIPS_ADD_IMMEDIATE"},
+       {35, "R_MIPS_PJUMP"},
+       {36, "R_MIPS_RELGOT"},
+       {37, "R_MIPS_JALR"},
+       {38, "R_MIPS_TLS_DTPMOD32"},
+       {39, "R_MIPS_TLS_DTPREL32"},
+       {40, "R_MIPS_TLS_DTPMOD64"},
+       {41, "R_MIPS_TLS_DTPREL64"},
+       {42, "R_MIPS_TLS_GD"},
+       {43, "R_MIPS_TLS_LDM"},
+       {44, "R_MIPS_TLS_DTPREL_HI16"},
+       {45, "R_MIPS_TLS_DTPREL_LO16"},
+       {46, "R_MIPS_TLS_GOTTPREL"},
+       {47, "R_MIPS_TLS_TPREL32"},
+       {48, "R_MIPS_TLS_TPREL64"},
+       {49, "R_MIPS_TLS_TPREL_HI16"},
+       {50, "R_MIPS_TLS_TPREL_LO16"},
+}
+
+func (i R_MIPS) String() string   { return stringName(uint32(i), rmipsStrings, false) }
+func (i R_MIPS) GoString() string { return stringName(uint32(i), rmipsStrings, true) }
+
 // Relocation types for PowerPC.
 type R_PPC int
 
@@ -1835,6 +1968,13 @@ type Dyn32 struct {
        Val uint32 /* Integer/Address value. */
 }
 
+// ELF32 Compression header.
+type Chdr32 struct {
+       Type      uint32
+       Size      uint32
+       Addralign uint32
+}
+
 /*
  * Relocation entries.
  */
@@ -1929,6 +2069,14 @@ type Dyn64 struct {
        Val uint64 /* Integer/address value */
 }
 
+// ELF64 Compression header.
+type Chdr64 struct {
+       Type      uint32
+       _         uint32 /* Reserved. */
+       Size      uint64
+       Addralign uint64
+}
+
 /*
  * Relocation entries.
  */
index 370c5e6437c94e5aaa34421a6d3fe41d708dbe95..b028772bfbf10cf6de4a732ad561054eb569cb5b 100644 (file)
@@ -7,6 +7,7 @@ package elf
 
 import (
        "bytes"
+       "compress/zlib"
        "debug/dwarf"
        "encoding/binary"
        "errors"
@@ -57,6 +58,12 @@ type SectionHeader struct {
        Info      uint32
        Addralign uint64
        Entsize   uint64
+
+       // FileSize is the size of this section in the file in bytes.
+       // If a section is compressed, FileSize is the size of the
+       // compressed data, while Size (above) is the size of the
+       // uncompressed data.
+       FileSize uint64
 }
 
 // A Section represents a single section in an ELF file.
@@ -69,17 +76,23 @@ type Section struct {
        // If a client wants Read and Seek it must use
        // Open() to avoid fighting over the seek offset
        // with other clients.
+       //
+       // ReaderAt may be nil if the section is not easily available
+       // in a random-access form. For example, a compressed section
+       // may have a nil ReaderAt.
        io.ReaderAt
        sr *io.SectionReader
+
+       compressionType   CompressionType
+       compressionOffset int64
 }
 
 // Data reads and returns the contents of the ELF section.
+// Even if the section is stored compressed in the ELF file,
+// Data returns uncompressed data.
 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
-       }
+       dat := make([]byte, s.Size)
+       n, err := io.ReadFull(s.Open(), dat)
        return dat[0:n], err
 }
 
@@ -93,7 +106,24 @@ func (f *File) stringTable(link uint32) ([]byte, error) {
 }
 
 // Open returns a new ReadSeeker reading the ELF section.
-func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
+// Even if the section is stored compressed in the ELF file,
+// the ReadSeeker reads uncompressed data.
+func (s *Section) Open() io.ReadSeeker {
+       if s.Flags&SHF_COMPRESSED == 0 {
+               return io.NewSectionReader(s.sr, 0, 1<<63-1)
+       }
+       if s.compressionType == COMPRESS_ZLIB {
+               return &readSeekerFromReader{
+                       reset: func() (io.Reader, error) {
+                               fr := io.NewSectionReader(s.sr, s.compressionOffset, int64(s.FileSize)-s.compressionOffset)
+                               return zlib.NewReader(fr)
+                       },
+                       size: int64(s.Size),
+               }
+       }
+       err := &FormatError{int64(s.Offset), "unknown compression type", s.compressionType}
+       return errorReader{err}
+}
 
 // A ProgHeader represents a single ELF program header.
 type ProgHeader struct {
@@ -343,7 +373,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
                                Flags:     SectionFlag(sh.Flags),
                                Addr:      uint64(sh.Addr),
                                Offset:    uint64(sh.Off),
-                               Size:      uint64(sh.Size),
+                               FileSize:  uint64(sh.Size),
                                Link:      uint32(sh.Link),
                                Info:      uint32(sh.Info),
                                Addralign: uint64(sh.Addralign),
@@ -359,7 +389,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
                                Type:      SectionType(sh.Type),
                                Flags:     SectionFlag(sh.Flags),
                                Offset:    uint64(sh.Off),
-                               Size:      uint64(sh.Size),
+                               FileSize:  uint64(sh.Size),
                                Addr:      uint64(sh.Addr),
                                Link:      uint32(sh.Link),
                                Info:      uint32(sh.Info),
@@ -367,8 +397,35 @@ func NewFile(r io.ReaderAt) (*File, error) {
                                Entsize:   uint64(sh.Entsize),
                        }
                }
-               s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size))
-               s.ReaderAt = s.sr
+               s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize))
+
+               if s.Flags&SHF_COMPRESSED == 0 {
+                       s.ReaderAt = s.sr
+                       s.Size = s.FileSize
+               } else {
+                       // Read the compression header.
+                       switch f.Class {
+                       case ELFCLASS32:
+                               ch := new(Chdr32)
+                               if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
+                                       return nil, err
+                               }
+                               s.compressionType = CompressionType(ch.Type)
+                               s.Size = uint64(ch.Size)
+                               s.Addralign = uint64(ch.Addralign)
+                               s.compressionOffset = int64(binary.Size(ch))
+                       case ELFCLASS64:
+                               ch := new(Chdr64)
+                               if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
+                                       return nil, err
+                               }
+                               s.compressionType = CompressionType(ch.Type)
+                               s.Size = ch.Size
+                               s.Addralign = ch.Addralign
+                               s.compressionOffset = int64(binary.Size(ch))
+                       }
+               }
+
                f.Sections[i] = s
        }
 
@@ -537,6 +594,8 @@ func (f *File) applyRelocations(dst []byte, rels []byte) error {
                return f.applyRelocationsPPC(dst, rels)
        case f.Class == ELFCLASS64 && f.Machine == EM_PPC64:
                return f.applyRelocationsPPC64(dst, rels)
+       case f.Class == ELFCLASS64 && f.Machine == EM_MIPS:
+               return f.applyRelocationsMIPS64(dst, rels)
        case f.Class == ELFCLASS64 && f.Machine == EM_S390:
                return f.applyRelocationsS390x(dst, rels)
        default:
@@ -802,6 +861,58 @@ func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
        return nil
 }
 
+func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {
+       // 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)
+       if err != nil {
+               return err
+       }
+
+       b := bytes.NewReader(rels)
+       var rela Rela64
+
+       for b.Len() > 0 {
+               binary.Read(b, f.ByteOrder, &rela)
+               var symNo uint64
+               var t R_MIPS
+               if f.ByteOrder == binary.BigEndian {
+                       symNo = rela.Info >> 32
+                       t = R_MIPS(rela.Info & 0xff)
+               } else {
+                       symNo = rela.Info & 0xffffffff
+                       t = R_MIPS(rela.Info >> 56)
+               }
+
+               if symNo == 0 || symNo > uint64(len(symbols)) {
+                       continue
+               }
+               sym := &symbols[symNo-1]
+               if SymType(sym.Info&0xf) != STT_SECTION {
+                       // We don't handle non-section relocations for now.
+                       continue
+               }
+
+               switch t {
+               case R_MIPS_64:
+                       if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
+                               continue
+                       }
+                       f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
+               case R_MIPS_32:
+                       if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
+                               continue
+                       }
+                       f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
+               }
+       }
+
+       return nil
+}
+
 func (f *File) applyRelocationsS390x(dst []byte, rels []byte) error {
        // 24 is the size of Rela64.
        if len(rels)%24 != 0 {
@@ -852,6 +963,22 @@ func (f *File) DWARF() (*dwarf.Data, error) {
                        return nil, err
                }
 
+               if len(b) >= 12 && string(b[:4]) == "ZLIB" {
+                       dlen := binary.BigEndian.Uint64(b[4:12])
+                       dbuf := make([]byte, dlen)
+                       r, err := zlib.NewReader(bytes.NewBuffer(b[12:]))
+                       if err != nil {
+                               return nil, err
+                       }
+                       if _, err := io.ReadFull(r, dbuf); err != nil {
+                               return nil, err
+                       }
+                       if err := r.Close(); err != nil {
+                               return nil, err
+                       }
+                       b = dbuf
+               }
+
                for _, r := range f.Sections {
                        if r.Type != SHT_RELA && r.Type != SHT_REL {
                                continue
@@ -876,17 +1003,23 @@ func (f *File) DWARF() (*dwarf.Data, error) {
        // Don't bother loading others.
        var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
        for i, s := range f.Sections {
-               if !strings.HasPrefix(s.Name, ".debug_") {
+               suffix := ""
+               switch {
+               case strings.HasPrefix(s.Name, ".debug_"):
+                       suffix = s.Name[7:]
+               case strings.HasPrefix(s.Name, ".zdebug_"):
+                       suffix = s.Name[8:]
+               default:
                        continue
                }
-               if _, ok := dat[s.Name[7:]]; !ok {
+               if _, ok := dat[suffix]; !ok {
                        continue
                }
                b, err := sectionData(i, s)
                if err != nil {
                        return nil, err
                }
-               dat[s.Name[7:]] = b
+               dat[suffix] = b
        }
 
        d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
index 1ad43146ac8b31858504d0c10e83d6d545b2437d..5c0df0f1e9eb937b72761780508cd0edfd9efe6b 100644 (file)
@@ -10,6 +10,7 @@ import (
        "debug/dwarf"
        "encoding/binary"
        "io"
+       "math/rand"
        "net"
        "os"
        "path"
@@ -31,36 +32,36 @@ var fileTests = []fileTest{
                "testdata/gcc-386-freebsd-exec",
                FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_FREEBSD, 0, binary.LittleEndian, ET_EXEC, EM_386, 0x80483cc},
                []SectionHeader{
-                       {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
-                       {".interp", SHT_PROGBITS, SHF_ALLOC, 0x80480d4, 0xd4, 0x15, 0x0, 0x0, 0x1, 0x0},
-                       {".hash", SHT_HASH, SHF_ALLOC, 0x80480ec, 0xec, 0x90, 0x3, 0x0, 0x4, 0x4},
-                       {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x804817c, 0x17c, 0x110, 0x4, 0x1, 0x4, 0x10},
-                       {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x804828c, 0x28c, 0xbb, 0x0, 0x0, 0x1, 0x0},
-                       {".rel.plt", SHT_REL, SHF_ALLOC, 0x8048348, 0x348, 0x20, 0x3, 0x7, 0x4, 0x8},
-                       {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x8048368, 0x368, 0x11, 0x0, 0x0, 0x4, 0x0},
-                       {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804837c, 0x37c, 0x50, 0x0, 0x0, 0x4, 0x4},
-                       {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x80483cc, 0x3cc, 0x180, 0x0, 0x0, 0x4, 0x0},
-                       {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804854c, 0x54c, 0xc, 0x0, 0x0, 0x4, 0x0},
-                       {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x8048558, 0x558, 0xa3, 0x0, 0x0, 0x1, 0x0},
-                       {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80495fc, 0x5fc, 0xc, 0x0, 0x0, 0x4, 0x0},
-                       {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x8049608, 0x608, 0x4, 0x0, 0x0, 0x4, 0x0},
-                       {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x804960c, 0x60c, 0x98, 0x4, 0x0, 0x4, 0x8},
-                       {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496a4, 0x6a4, 0x8, 0x0, 0x0, 0x4, 0x0},
-                       {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496ac, 0x6ac, 0x8, 0x0, 0x0, 0x4, 0x0},
-                       {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b4, 0x6b4, 0x4, 0x0, 0x0, 0x4, 0x0},
-                       {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b8, 0x6b8, 0x1c, 0x0, 0x0, 0x4, 0x4},
-                       {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x80496d4, 0x6d4, 0x20, 0x0, 0x0, 0x4, 0x0},
-                       {".comment", SHT_PROGBITS, 0x0, 0x0, 0x6d4, 0x12d, 0x0, 0x0, 0x1, 0x0},
-                       {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x801, 0x20, 0x0, 0x0, 0x1, 0x0},
-                       {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0x821, 0x1b, 0x0, 0x0, 0x1, 0x0},
-                       {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0x83c, 0x11d, 0x0, 0x0, 0x1, 0x0},
-                       {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0x959, 0x41, 0x0, 0x0, 0x1, 0x0},
-                       {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x99a, 0x35, 0x0, 0x0, 0x1, 0x0},
-                       {".debug_frame", SHT_PROGBITS, 0x0, 0x0, 0x9d0, 0x30, 0x0, 0x0, 0x4, 0x0},
-                       {".debug_str", SHT_PROGBITS, 0x0, 0x0, 0xa00, 0xd, 0x0, 0x0, 0x1, 0x0},
-                       {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xa0d, 0xf8, 0x0, 0x0, 0x1, 0x0},
-                       {".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10},
-                       {".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0},
+                       {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+                       {".interp", SHT_PROGBITS, SHF_ALLOC, 0x80480d4, 0xd4, 0x15, 0x0, 0x0, 0x1, 0x0, 0x15},
+                       {".hash", SHT_HASH, SHF_ALLOC, 0x80480ec, 0xec, 0x90, 0x3, 0x0, 0x4, 0x4, 0x90},
+                       {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x804817c, 0x17c, 0x110, 0x4, 0x1, 0x4, 0x10, 0x110},
+                       {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x804828c, 0x28c, 0xbb, 0x0, 0x0, 0x1, 0x0, 0xbb},
+                       {".rel.plt", SHT_REL, SHF_ALLOC, 0x8048348, 0x348, 0x20, 0x3, 0x7, 0x4, 0x8, 0x20},
+                       {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x8048368, 0x368, 0x11, 0x0, 0x0, 0x4, 0x0, 0x11},
+                       {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804837c, 0x37c, 0x50, 0x0, 0x0, 0x4, 0x4, 0x50},
+                       {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x80483cc, 0x3cc, 0x180, 0x0, 0x0, 0x4, 0x0, 0x180},
+                       {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804854c, 0x54c, 0xc, 0x0, 0x0, 0x4, 0x0, 0xc},
+                       {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x8048558, 0x558, 0xa3, 0x0, 0x0, 0x1, 0x0, 0xa3},
+                       {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80495fc, 0x5fc, 0xc, 0x0, 0x0, 0x4, 0x0, 0xc},
+                       {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x8049608, 0x608, 0x4, 0x0, 0x0, 0x4, 0x0, 0x4},
+                       {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x804960c, 0x60c, 0x98, 0x4, 0x0, 0x4, 0x8, 0x98},
+                       {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496a4, 0x6a4, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8},
+                       {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496ac, 0x6ac, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8},
+                       {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b4, 0x6b4, 0x4, 0x0, 0x0, 0x4, 0x0, 0x4},
+                       {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b8, 0x6b8, 0x1c, 0x0, 0x0, 0x4, 0x4, 0x1c},
+                       {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x80496d4, 0x6d4, 0x20, 0x0, 0x0, 0x4, 0x0, 0x20},
+                       {".comment", SHT_PROGBITS, 0x0, 0x0, 0x6d4, 0x12d, 0x0, 0x0, 0x1, 0x0, 0x12d},
+                       {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x801, 0x20, 0x0, 0x0, 0x1, 0x0, 0x20},
+                       {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0x821, 0x1b, 0x0, 0x0, 0x1, 0x0, 0x1b},
+                       {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0x83c, 0x11d, 0x0, 0x0, 0x1, 0x0, 0x11d},
+                       {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0x959, 0x41, 0x0, 0x0, 0x1, 0x0, 0x41},
+                       {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x99a, 0x35, 0x0, 0x0, 0x1, 0x0, 0x35},
+                       {".debug_frame", SHT_PROGBITS, 0x0, 0x0, 0x9d0, 0x30, 0x0, 0x0, 0x4, 0x0, 0x30},
+                       {".debug_str", SHT_PROGBITS, 0x0, 0x0, 0xa00, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd},
+                       {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xa0d, 0xf8, 0x0, 0x0, 0x1, 0x0, 0xf8},
+                       {".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10, 0x4b0},
+                       {".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0, 0x206},
                },
                []ProgHeader{
                        {PT_PHDR, PF_R + PF_X, 0x34, 0x8048034, 0x8048034, 0xa0, 0xa0, 0x4},
@@ -75,43 +76,43 @@ var fileTests = []fileTest{
                "testdata/gcc-amd64-linux-exec",
                FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0, binary.LittleEndian, ET_EXEC, EM_X86_64, 0x4003e0},
                []SectionHeader{
-                       {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
-                       {".interp", SHT_PROGBITS, SHF_ALLOC, 0x400200, 0x200, 0x1c, 0x0, 0x0, 0x1, 0x0},
-                       {".note.ABI-tag", SHT_NOTE, SHF_ALLOC, 0x40021c, 0x21c, 0x20, 0x0, 0x0, 0x4, 0x0},
-                       {".hash", SHT_HASH, SHF_ALLOC, 0x400240, 0x240, 0x24, 0x5, 0x0, 0x8, 0x4},
-                       {".gnu.hash", SHT_LOOS + 268435446, SHF_ALLOC, 0x400268, 0x268, 0x1c, 0x5, 0x0, 0x8, 0x0},
-                       {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x400288, 0x288, 0x60, 0x6, 0x1, 0x8, 0x18},
-                       {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x4002e8, 0x2e8, 0x3d, 0x0, 0x0, 0x1, 0x0},
-                       {".gnu.version", SHT_HIOS, SHF_ALLOC, 0x400326, 0x326, 0x8, 0x5, 0x0, 0x2, 0x2},
-                       {".gnu.version_r", SHT_LOOS + 268435454, SHF_ALLOC, 0x400330, 0x330, 0x20, 0x6, 0x1, 0x8, 0x0},
-                       {".rela.dyn", SHT_RELA, SHF_ALLOC, 0x400350, 0x350, 0x18, 0x5, 0x0, 0x8, 0x18},
-                       {".rela.plt", SHT_RELA, SHF_ALLOC, 0x400368, 0x368, 0x30, 0x5, 0xc, 0x8, 0x18},
-                       {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400398, 0x398, 0x18, 0x0, 0x0, 0x4, 0x0},
-                       {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003b0, 0x3b0, 0x30, 0x0, 0x0, 0x4, 0x10},
-                       {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003e0, 0x3e0, 0x1b4, 0x0, 0x0, 0x10, 0x0},
-                       {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400594, 0x594, 0xe, 0x0, 0x0, 0x4, 0x0},
-                       {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x4005a4, 0x5a4, 0x11, 0x0, 0x0, 0x4, 0x0},
-                       {".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 0x4005b8, 0x5b8, 0x24, 0x0, 0x0, 0x4, 0x0},
-                       {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x4005e0, 0x5e0, 0xa4, 0x0, 0x0, 0x8, 0x0},
-                       {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600688, 0x688, 0x10, 0x0, 0x0, 0x8, 0x0},
-                       {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600698, 0x698, 0x10, 0x0, 0x0, 0x8, 0x0},
-                       {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x6006a8, 0x6a8, 0x8, 0x0, 0x0, 0x8, 0x0},
-                       {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x6006b0, 0x6b0, 0x1a0, 0x6, 0x0, 0x8, 0x10},
-                       {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600850, 0x850, 0x8, 0x0, 0x0, 0x8, 0x8},
-                       {".got.plt", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600858, 0x858, 0x28, 0x0, 0x0, 0x8, 0x8},
-                       {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600880, 0x880, 0x18, 0x0, 0x0, 0x8, 0x0},
-                       {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x600898, 0x898, 0x8, 0x0, 0x0, 0x4, 0x0},
-                       {".comment", SHT_PROGBITS, 0x0, 0x0, 0x898, 0x126, 0x0, 0x0, 0x1, 0x0},
-                       {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x9c0, 0x90, 0x0, 0x0, 0x10, 0x0},
-                       {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0xa50, 0x25, 0x0, 0x0, 0x1, 0x0},
-                       {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0xa75, 0x1a7, 0x0, 0x0, 0x1, 0x0},
-                       {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xc1c, 0x6f, 0x0, 0x0, 0x1, 0x0},
-                       {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0xc8b, 0x13f, 0x0, 0x0, 0x1, 0x0},
-                       {".debug_str", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0xdca, 0xb1, 0x0, 0x0, 0x1, 0x1},
-                       {".debug_ranges", SHT_PROGBITS, 0x0, 0x0, 0xe80, 0x90, 0x0, 0x0, 0x10, 0x0},
-                       {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xf10, 0x149, 0x0, 0x0, 0x1, 0x0},
-                       {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18},
-                       {".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0},
+                       {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+                       {".interp", SHT_PROGBITS, SHF_ALLOC, 0x400200, 0x200, 0x1c, 0x0, 0x0, 0x1, 0x0, 0x1c},
+                       {".note.ABI-tag", SHT_NOTE, SHF_ALLOC, 0x40021c, 0x21c, 0x20, 0x0, 0x0, 0x4, 0x0, 0x20},
+                       {".hash", SHT_HASH, SHF_ALLOC, 0x400240, 0x240, 0x24, 0x5, 0x0, 0x8, 0x4, 0x24},
+                       {".gnu.hash", SHT_LOOS + 268435446, SHF_ALLOC, 0x400268, 0x268, 0x1c, 0x5, 0x0, 0x8, 0x0, 0x1c},
+                       {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x400288, 0x288, 0x60, 0x6, 0x1, 0x8, 0x18, 0x60},
+                       {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x4002e8, 0x2e8, 0x3d, 0x0, 0x0, 0x1, 0x0, 0x3d},
+                       {".gnu.version", SHT_HIOS, SHF_ALLOC, 0x400326, 0x326, 0x8, 0x5, 0x0, 0x2, 0x2, 0x8},
+                       {".gnu.version_r", SHT_LOOS + 268435454, SHF_ALLOC, 0x400330, 0x330, 0x20, 0x6, 0x1, 0x8, 0x0, 0x20},
+                       {".rela.dyn", SHT_RELA, SHF_ALLOC, 0x400350, 0x350, 0x18, 0x5, 0x0, 0x8, 0x18, 0x18},
+                       {".rela.plt", SHT_RELA, SHF_ALLOC, 0x400368, 0x368, 0x30, 0x5, 0xc, 0x8, 0x18, 0x30},
+                       {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400398, 0x398, 0x18, 0x0, 0x0, 0x4, 0x0, 0x18},
+                       {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003b0, 0x3b0, 0x30, 0x0, 0x0, 0x4, 0x10, 0x30},
+                       {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003e0, 0x3e0, 0x1b4, 0x0, 0x0, 0x10, 0x0, 0x1b4},
+                       {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400594, 0x594, 0xe, 0x0, 0x0, 0x4, 0x0, 0xe},
+                       {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x4005a4, 0x5a4, 0x11, 0x0, 0x0, 0x4, 0x0, 0x11},
+                       {".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 0x4005b8, 0x5b8, 0x24, 0x0, 0x0, 0x4, 0x0, 0x24},
+                       {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x4005e0, 0x5e0, 0xa4, 0x0, 0x0, 0x8, 0x0, 0xa4},
+                       {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600688, 0x688, 0x10, 0x0, 0x0, 0x8, 0x0, 0x10},
+                       {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600698, 0x698, 0x10, 0x0, 0x0, 0x8, 0x0, 0x10},
+                       {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x6006a8, 0x6a8, 0x8, 0x0, 0x0, 0x8, 0x0, 0x8},
+                       {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x6006b0, 0x6b0, 0x1a0, 0x6, 0x0, 0x8, 0x10, 0x1a0},
+                       {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600850, 0x850, 0x8, 0x0, 0x0, 0x8, 0x8, 0x8},
+                       {".got.plt", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600858, 0x858, 0x28, 0x0, 0x0, 0x8, 0x8, 0x28},
+                       {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600880, 0x880, 0x18, 0x0, 0x0, 0x8, 0x0, 0x18},
+                       {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x600898, 0x898, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8},
+                       {".comment", SHT_PROGBITS, 0x0, 0x0, 0x898, 0x126, 0x0, 0x0, 0x1, 0x0, 0x126},
+                       {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x9c0, 0x90, 0x0, 0x0, 0x10, 0x0, 0x90},
+                       {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0xa50, 0x25, 0x0, 0x0, 0x1, 0x0, 0x25},
+                       {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0xa75, 0x1a7, 0x0, 0x0, 0x1, 0x0, 0x1a7},
+                       {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xc1c, 0x6f, 0x0, 0x0, 0x1, 0x0, 0x6f},
+                       {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0xc8b, 0x13f, 0x0, 0x0, 0x1, 0x0, 0x13f},
+                       {".debug_str", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0xdca, 0xb1, 0x0, 0x0, 0x1, 0x1, 0xb1},
+                       {".debug_ranges", SHT_PROGBITS, 0x0, 0x0, 0xe80, 0x90, 0x0, 0x0, 0x10, 0x0, 0x90},
+                       {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xf10, 0x149, 0x0, 0x0, 0x1, 0x0, 0x149},
+                       {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18, 0x6f0},
+                       {".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0, 0x1fc},
                },
                []ProgHeader{
                        {PT_PHDR, PF_R + PF_X, 0x40, 0x400040, 0x400040, 0x1c0, 0x1c0, 0x8},
@@ -150,6 +151,64 @@ var fileTests = []fileTest{
                },
                nil,
        },
+       {
+               "testdata/compressed-32.obj",
+               FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_REL, EM_386, 0x0},
+               []SectionHeader{
+                       {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+                       {".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0x0, 0x34, 0x17, 0x0, 0x0, 0x1, 0x0, 0x17},
+                       {".rel.text", SHT_REL, SHF_INFO_LINK, 0x0, 0x3dc, 0x10, 0x13, 0x1, 0x4, 0x8, 0x10},
+                       {".data", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x4b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
+                       {".bss", SHT_NOBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x4b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
+                       {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x4b, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd},
+                       {".debug_info", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x58, 0xb4, 0x0, 0x0, 0x1, 0x0, 0x84},
+                       {".rel.debug_info", SHT_REL, SHF_INFO_LINK, 0x0, 0x3ec, 0xa0, 0x13, 0x6, 0x4, 0x8, 0xa0},
+                       {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xdc, 0x5a, 0x0, 0x0, 0x1, 0x0, 0x5a},
+                       {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x136, 0x20, 0x0, 0x0, 0x1, 0x0, 0x20},
+                       {".rel.debug_aranges", SHT_REL, SHF_INFO_LINK, 0x0, 0x48c, 0x10, 0x13, 0x9, 0x4, 0x8, 0x10},
+                       {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x156, 0x5c, 0x0, 0x0, 0x1, 0x0, 0x5c},
+                       {".rel.debug_line", SHT_REL, SHF_INFO_LINK, 0x0, 0x49c, 0x8, 0x13, 0xb, 0x4, 0x8, 0x8},
+                       {".debug_str", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED, 0x0, 0x1b2, 0x10f, 0x0, 0x0, 0x1, 0x1, 0xb3},
+                       {".comment", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS, 0x0, 0x265, 0x2a, 0x0, 0x0, 0x1, 0x1, 0x2a},
+                       {".note.GNU-stack", SHT_PROGBITS, 0x0, 0x0, 0x28f, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
+                       {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x290, 0x38, 0x0, 0x0, 0x4, 0x0, 0x38},
+                       {".rel.eh_frame", SHT_REL, SHF_INFO_LINK, 0x0, 0x4a4, 0x8, 0x13, 0x10, 0x4, 0x8, 0x8},
+                       {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0x4ac, 0xab, 0x0, 0x0, 0x1, 0x0, 0xab},
+                       {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x2c8, 0x100, 0x14, 0xe, 0x4, 0x10, 0x100},
+                       {".strtab", SHT_STRTAB, 0x0, 0x0, 0x3c8, 0x13, 0x0, 0x0, 0x1, 0x0, 0x13},
+               },
+               []ProgHeader{},
+               nil,
+       },
+       {
+               "testdata/compressed-64.obj",
+               FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_REL, EM_X86_64, 0x0},
+               []SectionHeader{
+                       {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+                       {".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0x0, 0x40, 0x1b, 0x0, 0x0, 0x1, 0x0, 0x1b},
+                       {".rela.text", SHT_RELA, SHF_INFO_LINK, 0x0, 0x488, 0x30, 0x13, 0x1, 0x8, 0x18, 0x30},
+                       {".data", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x5b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
+                       {".bss", SHT_NOBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x5b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
+                       {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x5b, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd},
+                       {".debug_info", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x68, 0xba, 0x0, 0x0, 0x1, 0x0, 0x72},
+                       {".rela.debug_info", SHT_RELA, SHF_INFO_LINK, 0x0, 0x4b8, 0x1c8, 0x13, 0x6, 0x8, 0x18, 0x1c8},
+                       {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xda, 0x5c, 0x0, 0x0, 0x1, 0x0, 0x5c},
+                       {".debug_aranges", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x136, 0x30, 0x0, 0x0, 0x1, 0x0, 0x2f},
+                       {".rela.debug_aranges", SHT_RELA, SHF_INFO_LINK, 0x0, 0x680, 0x30, 0x13, 0x9, 0x8, 0x18, 0x30},
+                       {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x165, 0x60, 0x0, 0x0, 0x1, 0x0, 0x60},
+                       {".rela.debug_line", SHT_RELA, SHF_INFO_LINK, 0x0, 0x6b0, 0x18, 0x13, 0xb, 0x8, 0x18, 0x18},
+                       {".debug_str", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED, 0x0, 0x1c5, 0x104, 0x0, 0x0, 0x1, 0x1, 0xc3},
+                       {".comment", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS, 0x0, 0x288, 0x2a, 0x0, 0x0, 0x1, 0x1, 0x2a},
+                       {".note.GNU-stack", SHT_PROGBITS, 0x0, 0x0, 0x2b2, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
+                       {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x2b8, 0x38, 0x0, 0x0, 0x8, 0x0, 0x38},
+                       {".rela.eh_frame", SHT_RELA, SHF_INFO_LINK, 0x0, 0x6c8, 0x18, 0x13, 0x10, 0x8, 0x18, 0x18},
+                       {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0x6e0, 0xb0, 0x0, 0x0, 0x1, 0x0, 0xb0},
+                       {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x2f0, 0x180, 0x14, 0xe, 0x8, 0x18, 0x180},
+                       {".strtab", SHT_STRTAB, 0x0, 0x0, 0x470, 0x13, 0x0, 0x0, 0x1, 0x0, 0x13},
+               },
+               []ProgHeader{},
+               nil,
+       },
 }
 
 func TestOpen(t *testing.T) {
@@ -245,62 +304,237 @@ var relocationTests = []relocationTest{
        {
                "testdata/go-relocation-test-gcc441-x86-64.obj",
                []relocationTestEntry{
-                       {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}},
+                       {0, &dwarf.Entry{
+                               Offset:   0xb,
+                               Tag:      dwarf.TagCompileUnit,
+                               Children: true,
+                               Field: []dwarf.Field{
+                                       {Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrName, Val: "go-relocation-test.c", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
+                                       {Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress},
+                                       {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
+                               },
+                       }},
                },
        },
        {
                "testdata/go-relocation-test-gcc441-x86.obj",
                []relocationTestEntry{
-                       {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "t.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}},
+                       {0, &dwarf.Entry{
+                               Offset:   0xb,
+                               Tag:      dwarf.TagCompileUnit,
+                               Children: true,
+                               Field: []dwarf.Field{
+                                       {Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrName, Val: "t.c", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
+                                       {Attr: dwarf.AttrHighpc, Val: uint64(0x5), Class: dwarf.ClassAddress},
+                                       {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
+                               },
+                       }},
                },
        },
        {
                "testdata/go-relocation-test-gcc424-x86-64.obj",
                []relocationTestEntry{
-                       {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}},
+                       {0, &dwarf.Entry{
+                               Offset:   0xb,
+                               Tag:      dwarf.TagCompileUnit,
+                               Children: true,
+                               Field: []dwarf.Field{
+                                       {Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
+                                       {Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress},
+                                       {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
+                               },
+                       }},
                },
        },
        {
                "testdata/go-relocation-test-gcc482-aarch64.obj",
                []relocationTestEntry{
-                       {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: int64(0x24), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}},
+                       {0, &dwarf.Entry{
+                               Offset:   0xb,
+                               Tag:      dwarf.TagCompileUnit,
+                               Children: true,
+                               Field: []dwarf.Field{
+                                       {Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
+                                       {Attr: dwarf.AttrHighpc, Val: int64(0x24), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
+                               },
+                       }},
                },
        },
        {
                "testdata/go-relocation-test-gcc492-arm.obj",
                []relocationTestEntry{
-                       {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 20141224 (prerelease) -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -mtls-dialect=gnu -g", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc492.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/root/go/src/debug/elf/testdata", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: int64(0x28), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}},
+                       {0, &dwarf.Entry{
+                               Offset:   0xb,
+                               Tag:      dwarf.TagCompileUnit,
+                               Children: true,
+                               Field: []dwarf.Field{
+                                       {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 20141224 (prerelease) -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -mtls-dialect=gnu -g", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc492.c", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrCompDir, Val: "/root/go/src/debug/elf/testdata", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
+                                       {Attr: dwarf.AttrHighpc, Val: int64(0x28), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
+                               },
+                       }},
                },
        },
        {
                "testdata/go-relocation-test-clang-arm.obj",
                []relocationTestEntry{
-                       {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0x0), Class: dwarf.ClassLinePtr}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: int64(48), Class: dwarf.ClassConstant}}}},
+                       {0, &dwarf.Entry{
+                               Offset:   0xb,
+                               Tag:      dwarf.TagCompileUnit,
+                               Children: true,
+                               Field: []dwarf.Field{
+                                       {Attr: dwarf.AttrProducer, Val: "Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrStmtList, Val: int64(0x0), Class: dwarf.ClassLinePtr},
+                                       {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
+                                       {Attr: dwarf.AttrHighpc, Val: int64(48), Class: dwarf.ClassConstant},
+                               },
+                       }},
                },
        },
        {
                "testdata/go-relocation-test-gcc5-ppc.obj",
                []relocationTestEntry{
-                       {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C11 5.0.0 20150116 (experimental) -Asystem=linux -Asystem=unix -Asystem=posix -g", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc5-ppc.c", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: int64(0x44), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}},
+                       {0, &dwarf.Entry{
+                               Offset:   0xb,
+                               Tag:      dwarf.TagCompileUnit,
+                               Children: true,
+                               Field: []dwarf.Field{
+                                       {Attr: dwarf.AttrProducer, Val: "GNU C11 5.0.0 20150116 (experimental) -Asystem=linux -Asystem=unix -Asystem=posix -g", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc5-ppc.c", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
+                                       {Attr: dwarf.AttrHighpc, Val: int64(0x44), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
+                               },
+                       }},
                },
        },
        {
                "testdata/go-relocation-test-gcc482-ppc64le.obj",
                []relocationTestEntry{
-                       {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -Asystem=linux -Asystem=unix -Asystem=posix -msecure-plt -mtune=power8 -mcpu=power7 -gdwarf-2 -fstack-protector", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: uint64(0x24), Class: dwarf.ClassAddress}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}},
+                       {0, &dwarf.Entry{
+                               Offset:   0xb,
+                               Tag:      dwarf.TagCompileUnit,
+                               Children: true,
+                               Field: []dwarf.Field{
+                                       {Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -Asystem=linux -Asystem=unix -Asystem=posix -msecure-plt -mtune=power8 -mcpu=power7 -gdwarf-2 -fstack-protector", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
+                                       {Attr: dwarf.AttrHighpc, Val: uint64(0x24), Class: dwarf.ClassAddress},
+                                       {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
+                               },
+                       }},
+               },
+       },
+       {
+               "testdata/go-relocation-test-gcc492-mips64.obj",
+               []relocationTestEntry{
+                       {0, &dwarf.Entry{
+                               Offset:   0xb,
+                               Tag:      dwarf.TagCompileUnit,
+                               Children: true,
+                               Field: []dwarf.Field{
+                                       {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 -meb -mabi=64 -march=mips3 -mtune=mips64 -mllsc -mno-shared -g", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
+                                       {Attr: dwarf.AttrHighpc, Val: int64(100), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
+                               },
+                       }},
+               },
+       },
+       {
+               "testdata/go-relocation-test-gcc493-mips64le.obj",
+               []relocationTestEntry{
+                       {0, &dwarf.Entry{
+                               Offset:   0xb,
+                               Tag:      dwarf.TagCompileUnit,
+                               Children: true,
+                               Field: []dwarf.Field{
+                                       {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.3 -mel -mabi=64 -mllsc -mno-shared -g -fstack-protector-strong", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
+                                       {Attr: dwarf.AttrHighpc, Val: int64(100), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
+                               },
+                       }},
                },
        },
        {
                "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)", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}}}},
+                       {0, &dwarf.Entry{
+                               Offset:   0xb,
+                               Tag:      dwarf.TagCompileUnit,
+                               Children: true,
+                               Field: []dwarf.Field{
+                                       {Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
+                                       {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
+                               },
+                       }},
                },
        },
        {
                "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", Class: dwarf.ClassString}, {Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrDeclLine, Val: int64(236), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}, Class: dwarf.ClassExprLoc}}}},
-                       {204, &dwarf.Entry{Offset: 0xc70, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_value", Class: dwarf.ClassString}, {Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrDeclLine, Val: int64(237), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}, Class: dwarf.ClassExprLoc}}}},
+                       {203, &dwarf.Entry{
+                               Offset:   0xc62,
+                               Tag:      dwarf.TagMember,
+                               Children: false,
+                               Field: []dwarf.Field{
+                                       {Attr: dwarf.AttrName, Val: "it_interval", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrDeclLine, Val: int64(236), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference},
+                                       {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}, Class: dwarf.ClassExprLoc},
+                               },
+                       }},
+                       {204, &dwarf.Entry{
+                               Offset:   0xc70,
+                               Tag:      dwarf.TagMember,
+                               Children: false,
+                               Field: []dwarf.Field{
+                                       {Attr: dwarf.AttrName, Val: "it_value", Class: dwarf.ClassString},
+                                       {Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrDeclLine, Val: int64(237), Class: dwarf.ClassConstant},
+                                       {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference},
+                                       {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}, Class: dwarf.ClassExprLoc},
+                               },
+                       }},
                },
        },
 }
@@ -339,6 +573,119 @@ func TestDWARFRelocations(t *testing.T) {
        }
 }
 
+func TestCompressedDWARF(t *testing.T) {
+       // Test file built with GCC 4.8.4 and as 2.24 using:
+       // gcc -Wa,--compress-debug-sections -g -c -o zdebug-test-gcc484-x86-64.obj hello.c
+       f, err := Open("testdata/zdebug-test-gcc484-x86-64.obj")
+       if err != nil {
+               t.Fatal(err)
+       }
+       dwarf, err := f.DWARF()
+       if err != nil {
+               t.Fatal(err)
+       }
+       reader := dwarf.Reader()
+       n := 0
+       for {
+               entry, err := reader.Next()
+               if err != nil {
+                       t.Fatal(err)
+               }
+               if entry == nil {
+                       break
+               }
+               n++
+       }
+       if n != 18 {
+               t.Fatalf("want %d DWARF entries, got %d", 18, n)
+       }
+}
+
+func TestCompressedSection(t *testing.T) {
+       // Test files built with gcc -g -S hello.c and assembled with
+       // --compress-debug-sections=zlib-gabi.
+       f, err := Open("testdata/compressed-64.obj")
+       if err != nil {
+               t.Fatal(err)
+       }
+       sec := f.Section(".debug_info")
+       wantData := []byte{
+               182, 0, 0, 0, 4, 0, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0,
+               1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 7,
+               0, 0, 0, 0, 2, 1, 8, 0, 0, 0, 0, 2, 2, 7, 0, 0,
+               0, 0, 2, 4, 7, 0, 0, 0, 0, 2, 1, 6, 0, 0, 0, 0,
+               2, 2, 5, 0, 0, 0, 0, 3, 4, 5, 105, 110, 116, 0, 2, 8,
+               5, 0, 0, 0, 0, 2, 8, 7, 0, 0, 0, 0, 4, 8, 114, 0,
+               0, 0, 2, 1, 6, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 4,
+               0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0,
+               1, 156, 179, 0, 0, 0, 6, 0, 0, 0, 0, 1, 4, 87, 0, 0,
+               0, 2, 145, 108, 6, 0, 0, 0, 0, 1, 4, 179, 0, 0, 0, 2,
+               145, 96, 0, 4, 8, 108, 0, 0, 0, 0,
+       }
+
+       // Test Data method.
+       b, err := sec.Data()
+       if err != nil {
+               t.Fatal(err)
+       }
+       if !bytes.Equal(wantData, b) {
+               t.Fatalf("want data %x, got %x", wantData, b)
+       }
+
+       // Test Open method and seeking.
+       buf, have, count := make([]byte, len(b)), make([]bool, len(b)), 0
+       sf := sec.Open()
+       if got, err := sf.Seek(0, 2); got != int64(len(b)) || err != nil {
+               t.Fatalf("want seek end %d, got %d error %v", len(b), got, err)
+       }
+       if n, err := sf.Read(buf); n != 0 || err != io.EOF {
+               t.Fatalf("want EOF with 0 bytes, got %v with %d bytes", err, n)
+       }
+       pos := int64(len(buf))
+       for count < len(buf) {
+               // Construct random seek arguments.
+               whence := rand.Intn(3)
+               target := rand.Int63n(int64(len(buf)))
+               var offset int64
+               switch whence {
+               case 0:
+                       offset = target
+               case 1:
+                       offset = target - pos
+               case 2:
+                       offset = target - int64(len(buf))
+               }
+               pos, err = sf.Seek(offset, whence)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               if pos != target {
+                       t.Fatalf("want position %d, got %d", target, pos)
+               }
+
+               // Read data from the new position.
+               end := pos + 16
+               if end > int64(len(buf)) {
+                       end = int64(len(buf))
+               }
+               n, err := sf.Read(buf[pos:end])
+               if err != nil {
+                       t.Fatal(err)
+               }
+               for i := 0; i < n; i++ {
+                       if !have[pos] {
+                               have[pos] = true
+                               count++
+                       }
+                       pos++
+               }
+       }
+       if !bytes.Equal(wantData, buf) {
+               t.Fatalf("want data %x, got %x", wantData, buf)
+       }
+}
+
 func TestNoSectionOverlaps(t *testing.T) {
        // Ensure 6l outputs sections without overlaps.
        if runtime.GOOS != "linux" && runtime.GOOS != "freebsd" {
diff --git a/libgo/go/debug/elf/reader.go b/libgo/go/debug/elf/reader.go
new file mode 100644 (file)
index 0000000..17b5716
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright 2015 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 elf
+
+import (
+       "io"
+       "os"
+)
+
+// errorReader returns error from all operations.
+type errorReader struct {
+       error
+}
+
+func (r errorReader) Read(p []byte) (n int, err error) {
+       return 0, r.error
+}
+
+func (r errorReader) ReadAt(p []byte, off int64) (n int, err error) {
+       return 0, r.error
+}
+
+func (r errorReader) Seek(offset int64, whence int) (int64, error) {
+       return 0, r.error
+}
+
+func (r errorReader) Close() error {
+       return r.error
+}
+
+// readSeekerFromReader converts an io.Reader into an io.ReadSeeker.
+// In general Seek may not be efficient, but it is optimized for
+// common cases such as seeking to the end to find the length of the
+// data.
+type readSeekerFromReader struct {
+       reset  func() (io.Reader, error)
+       r      io.Reader
+       size   int64
+       offset int64
+}
+
+func (r *readSeekerFromReader) start() {
+       x, err := r.reset()
+       if err != nil {
+               r.r = errorReader{err}
+       } else {
+               r.r = x
+       }
+       r.offset = 0
+}
+
+func (r *readSeekerFromReader) Read(p []byte) (n int, err error) {
+       if r.r == nil {
+               r.start()
+       }
+       n, err = r.r.Read(p)
+       r.offset += int64(n)
+       return n, err
+}
+
+func (r *readSeekerFromReader) Seek(offset int64, whence int) (int64, error) {
+       var newOffset int64
+       switch whence {
+       case 0:
+               newOffset = offset
+       case 1:
+               newOffset = r.offset + offset
+       case 2:
+               newOffset = r.size + offset
+       default:
+               return 0, os.ErrInvalid
+       }
+
+       switch {
+       case newOffset == r.offset:
+               return newOffset, nil
+
+       case newOffset < 0, newOffset > r.size:
+               return 0, os.ErrInvalid
+
+       case newOffset == 0:
+               r.r = nil
+
+       case newOffset == r.size:
+               r.r = errorReader{io.EOF}
+
+       default:
+               if newOffset < r.offset {
+                       // Restart at the beginning.
+                       r.start()
+               }
+               // Read until we reach offset.
+               var buf [512]byte
+               for r.offset < newOffset {
+                       b := buf[:]
+                       if newOffset-r.offset < int64(len(buf)) {
+                               b = buf[:newOffset-r.offset]
+                       }
+                       if _, err := r.Read(b); err != nil {
+                               return 0, err
+                       }
+               }
+       }
+       r.offset = newOffset
+       return r.offset, nil
+}
diff --git a/libgo/go/debug/elf/testdata/compressed-32.obj b/libgo/go/debug/elf/testdata/compressed-32.obj
new file mode 100644 (file)
index 0000000..2bfdb44
Binary files /dev/null and b/libgo/go/debug/elf/testdata/compressed-32.obj differ
diff --git a/libgo/go/debug/elf/testdata/compressed-64.obj b/libgo/go/debug/elf/testdata/compressed-64.obj
new file mode 100644 (file)
index 0000000..ffae56a
Binary files /dev/null and b/libgo/go/debug/elf/testdata/compressed-64.obj differ
diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc492-mips64.obj b/libgo/go/debug/elf/testdata/go-relocation-test-gcc492-mips64.obj
new file mode 100644 (file)
index 0000000..68febe1
Binary files /dev/null and b/libgo/go/debug/elf/testdata/go-relocation-test-gcc492-mips64.obj differ
diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc493-mips64le.obj b/libgo/go/debug/elf/testdata/go-relocation-test-gcc493-mips64le.obj
new file mode 100644 (file)
index 0000000..20bbd6c
Binary files /dev/null and b/libgo/go/debug/elf/testdata/go-relocation-test-gcc493-mips64le.obj differ
diff --git a/libgo/go/debug/elf/testdata/zdebug-test-gcc484-x86-64.obj b/libgo/go/debug/elf/testdata/zdebug-test-gcc484-x86-64.obj
new file mode 100644 (file)
index 0000000..a595a01
Binary files /dev/null and b/libgo/go/debug/elf/testdata/zdebug-test-gcc484-x86-64.obj differ
index 53f3e952d62bdbf7f2d12c535aa701ecedc45da5..8d4aa547a020b38e3b4eeae3abf3bf1d09b68f42 100644 (file)
@@ -6,6 +6,7 @@ package gosym
 
 import (
        "debug/elf"
+       "internal/testenv"
        "io/ioutil"
        "os"
        "os/exec"
@@ -20,25 +21,16 @@ var (
        pclinetestBinary string
 )
 
-func dotest(self bool) bool {
+func dotest(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
        // For now, only works on amd64 platforms.
        if runtime.GOARCH != "amd64" {
-               return false
-       }
-       // Self test reads test binary; only works on Linux.
-       if self && runtime.GOOS != "linux" {
-               return false
-       }
-       if pclinetestBinary != "" {
-               return true
+               t.Skipf("skipping on non-AMD64 system %s", runtime.GOARCH)
        }
        var err error
        pclineTempDir, err = ioutil.TempDir("", "pclinetest")
        if err != nil {
-               panic(err)
-       }
-       if strings.Contains(pclineTempDir, " ") {
-               panic("unexpected space in tempdir")
+               t.Fatal(err)
        }
        // This command builds pclinetest from pclinetest.asm;
        // the resulting binary looks like it was built from pclinetest.s,
@@ -48,16 +40,15 @@ func dotest(self bool) bool {
        cmd.Stdout = os.Stdout
        cmd.Stderr = os.Stderr
        if err := cmd.Run(); err != nil {
-               panic(err)
+               t.Fatal(err)
        }
        cmd = exec.Command("go", "tool", "link", "-H", "linux", "-E", "main",
                "-o", pclinetestBinary, pclinetestBinary+".o")
        cmd.Stdout = os.Stdout
        cmd.Stderr = os.Stderr
        if err := cmd.Run(); err != nil {
-               panic(err)
+               t.Fatal(err)
        }
-       return true
 }
 
 func endtest() {
@@ -68,6 +59,17 @@ func endtest() {
        }
 }
 
+// skipIfNotELF skips the test if we are not running on an ELF system.
+// These tests open and examine the test binary, and use elf.Open to do so.
+func skipIfNotELF(t *testing.T) {
+       switch runtime.GOOS {
+       case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
+               // OK.
+       default:
+               t.Skipf("skipping on non-ELF system %s", runtime.GOOS)
+       }
+}
+
 func getTable(t *testing.T) *Table {
        f, tab := crack(os.Args[0], t)
        f.Close()
@@ -112,10 +114,7 @@ func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
 var goarch = os.Getenv("O")
 
 func TestLineFromAline(t *testing.T) {
-       if !dotest(true) {
-               return
-       }
-       defer endtest()
+       skipIfNotELF(t)
 
        tab := getTable(t)
        if tab.go12line != nil {
@@ -164,10 +163,7 @@ func TestLineFromAline(t *testing.T) {
 }
 
 func TestLineAline(t *testing.T) {
-       if !dotest(true) {
-               return
-       }
-       defer endtest()
+       skipIfNotELF(t)
 
        tab := getTable(t)
        if tab.go12line != nil {
@@ -210,9 +206,7 @@ func TestLineAline(t *testing.T) {
 }
 
 func TestPCLine(t *testing.T) {
-       if !dotest(false) {
-               return
-       }
+       dotest(t)
        defer endtest()
 
        f, tab := crack(pclinetestBinary, t)
index 2ac411af8820b7c2c8f22f5f442307a3810ec27d..8bafefd52bb463dde5ae5e9c85216d8916a9ee0d 100644 (file)
@@ -71,9 +71,28 @@ func parseBool(bytes []byte) (ret bool, err error) {
 
 // INTEGER
 
+// checkInteger returns nil if the given bytes are a valid DER-encoded
+// INTEGER and an error otherwise.
+func checkInteger(bytes []byte) error {
+       if len(bytes) == 0 {
+               return StructuralError{"empty integer"}
+       }
+       if len(bytes) == 1 {
+               return nil
+       }
+       if (bytes[0] == 0 && bytes[1]&0x80 == 0) || (bytes[0] == 0xff && bytes[1]&0x80 == 0x80) {
+               return StructuralError{"integer not minimally-encoded"}
+       }
+       return nil
+}
+
 // parseInt64 treats the given bytes as a big-endian, signed integer and
 // returns the result.
 func parseInt64(bytes []byte) (ret int64, err error) {
+       err = checkInteger(bytes)
+       if err != nil {
+               return
+       }
        if len(bytes) > 8 {
                // We'll overflow an int64 in this case.
                err = StructuralError{"integer too large"}
@@ -93,6 +112,9 @@ func parseInt64(bytes []byte) (ret int64, err error) {
 // parseInt treats the given bytes as a big-endian, signed integer and returns
 // the result.
 func parseInt32(bytes []byte) (int32, error) {
+       if err := checkInteger(bytes); err != nil {
+               return 0, err
+       }
        ret64, err := parseInt64(bytes)
        if err != nil {
                return 0, err
@@ -107,7 +129,10 @@ var bigOne = big.NewInt(1)
 
 // parseBigInt treats the given bytes as a big-endian, signed integer and returns
 // the result.
-func parseBigInt(bytes []byte) *big.Int {
+func parseBigInt(bytes []byte) (*big.Int, error) {
+       if err := checkInteger(bytes); err != nil {
+               return nil, err
+       }
        ret := new(big.Int)
        if len(bytes) > 0 && bytes[0]&0x80 == 0x80 {
                // This is a negative number.
@@ -118,10 +143,10 @@ func parseBigInt(bytes []byte) *big.Int {
                ret.SetBytes(notBytes)
                ret.Add(ret, bigOne)
                ret.Neg(ret)
-               return ret
+               return ret, nil
        }
        ret.SetBytes(bytes)
-       return ret
+       return ret, nil
 }
 
 // BIT STRING
@@ -269,7 +294,7 @@ type Flag bool
 func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error) {
        offset = initOffset
        for shifted := 0; offset < len(bytes); shifted++ {
-               if shifted > 4 {
+               if shifted == 4 {
                        err = StructuralError{"base 128 integer too large"}
                        return
                }
@@ -475,6 +500,11 @@ func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset i
                                return
                        }
                }
+               // Short lengths must be encoded in short form.
+               if ret.length < 0x80 {
+                       err = StructuralError{"non-minimal length"}
+                       return
+               }
        }
 
        return
@@ -500,17 +530,17 @@ func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type
                        return
                }
                switch t.tag {
-               case tagIA5String, tagGeneralString, tagT61String, tagUTF8String:
+               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:
+                       t.tag = TagPrintableString
+               case TagGeneralizedTime, TagUTCTime:
                        // Likewise, both time types are treated the same.
-                       t.tag = tagUTCTime
+                       t.tag = TagUTCTime
                }
 
-               if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag {
+               if t.class != ClassUniversal || t.isCompound != compoundType || t.tag != expectedTag {
                        err = StructuralError{"sequence tag mismatch"}
                        return
                }
@@ -594,28 +624,28 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
                        return
                }
                var result interface{}
-               if !t.isCompound && t.class == classUniversal {
+               if !t.isCompound && t.class == ClassUniversal {
                        innerBytes := bytes[offset : offset+t.length]
                        switch t.tag {
-                       case tagPrintableString:
+                       case TagPrintableString:
                                result, err = parsePrintableString(innerBytes)
-                       case tagIA5String:
+                       case TagIA5String:
                                result, err = parseIA5String(innerBytes)
-                       case tagT61String:
+                       case TagT61String:
                                result, err = parseT61String(innerBytes)
-                       case tagUTF8String:
+                       case TagUTF8String:
                                result, err = parseUTF8String(innerBytes)
-                       case tagInteger:
+                       case TagInteger:
                                result, err = parseInt64(innerBytes)
-                       case tagBitString:
+                       case TagBitString:
                                result, err = parseBitString(innerBytes)
-                       case tagOID:
+                       case TagOID:
                                result, err = parseObjectIdentifier(innerBytes)
-                       case tagUTCTime:
+                       case TagUTCTime:
                                result, err = parseUTCTime(innerBytes)
-                       case tagGeneralizedTime:
+                       case TagGeneralizedTime:
                                result, err = parseGeneralizedTime(innerBytes)
-                       case tagOctetString:
+                       case TagOctetString:
                                result = innerBytes
                        default:
                                // If we don't know how to handle the type, we just leave Value as nil.
@@ -641,9 +671,9 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
                return
        }
        if params.explicit {
-               expectedClass := classContextSpecific
+               expectedClass := ClassContextSpecific
                if params.application {
-                       expectedClass = classApplication
+                       expectedClass = ClassApplication
                }
                if offset == len(bytes) {
                        err = StructuralError{"explicit tag has no child"}
@@ -679,10 +709,10 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
        // type string. getUniversalType returns the tag for PrintableString
        // when it sees a string, so if we see a different string type on the
        // wire, we change the universal type to match.
-       if universalTag == tagPrintableString {
-               if t.class == classUniversal {
+       if universalTag == TagPrintableString {
+               if t.class == ClassUniversal {
                        switch t.tag {
-                       case tagIA5String, tagGeneralString, tagT61String, tagUTF8String:
+                       case TagIA5String, TagGeneralString, TagT61String, TagUTF8String:
                                universalTag = t.tag
                        }
                } else if params.stringType != 0 {
@@ -692,24 +722,24 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
 
        // Special case for time: UTCTime and GeneralizedTime both map to the
        // Go type time.Time.
-       if universalTag == tagUTCTime && t.tag == tagGeneralizedTime && t.class == classUniversal {
-               universalTag = tagGeneralizedTime
+       if universalTag == TagUTCTime && t.tag == TagGeneralizedTime && t.class == ClassUniversal {
+               universalTag = TagGeneralizedTime
        }
 
        if params.set {
-               universalTag = tagSet
+               universalTag = TagSet
        }
 
-       expectedClass := classUniversal
+       expectedClass := ClassUniversal
        expectedTag := universalTag
 
        if !params.explicit && params.tag != nil {
-               expectedClass = classContextSpecific
+               expectedClass = ClassContextSpecific
                expectedTag = *params.tag
        }
 
        if !params.explicit && params.application && params.tag != nil {
-               expectedClass = classApplication
+               expectedClass = ClassApplication
                expectedTag = *params.tag
        }
 
@@ -751,7 +781,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
        case timeType:
                var time time.Time
                var err1 error
-               if universalTag == tagUTCTime {
+               if universalTag == TagUTCTime {
                        time, err1 = parseUTCTime(innerBytes)
                } else {
                        time, err1 = parseGeneralizedTime(innerBytes)
@@ -772,8 +802,11 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
                v.SetBool(true)
                return
        case bigIntType:
-               parsedInt := parseBigInt(innerBytes)
-               v.Set(reflect.ValueOf(parsedInt))
+               parsedInt, err1 := parseBigInt(innerBytes)
+               if err1 == nil {
+                       v.Set(reflect.ValueOf(parsedInt))
+               }
+               err = err1
                return
        }
        switch val := v; val.Kind() {
@@ -840,15 +873,15 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
        case reflect.String:
                var v string
                switch universalTag {
-               case tagPrintableString:
+               case TagPrintableString:
                        v, err = parsePrintableString(innerBytes)
-               case tagIA5String:
+               case TagIA5String:
                        v, err = parseIA5String(innerBytes)
-               case tagT61String:
+               case TagT61String:
                        v, err = parseT61String(innerBytes)
-               case tagUTF8String:
+               case TagUTF8String:
                        v, err = parseUTF8String(innerBytes)
-               case tagGeneralString:
+               case TagGeneralString:
                        // GeneralString is specified in ISO-2022/ECMA-35,
                        // A brief review suggests that it includes structures
                        // that allow the encoding to change midstring and
index 893d0801b00308ffd935d6d26426631fe3e9efc6..e0e833123b155ff838ad01438c3285cd61730fdc 100644 (file)
@@ -53,10 +53,12 @@ var int64TestData = []int64Test{
        {[]byte{0x01, 0x00}, true, 256},
        {[]byte{0x80}, true, -128},
        {[]byte{0xff, 0x7f}, true, -129},
-       {[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, true, -1},
        {[]byte{0xff}, true, -1},
        {[]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, true, -9223372036854775808},
        {[]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, false, 0},
+       {[]byte{}, false, 0},
+       {[]byte{0x00, 0x7f}, false, 0},
+       {[]byte{0xff, 0xf0}, false, 0},
 }
 
 func TestParseInt64(t *testing.T) {
@@ -84,10 +86,12 @@ var int32TestData = []int32Test{
        {[]byte{0x01, 0x00}, true, 256},
        {[]byte{0x80}, true, -128},
        {[]byte{0xff, 0x7f}, true, -129},
-       {[]byte{0xff, 0xff, 0xff, 0xff}, true, -1},
        {[]byte{0xff}, true, -1},
        {[]byte{0x80, 0x00, 0x00, 0x00}, true, -2147483648},
        {[]byte{0x80, 0x00, 0x00, 0x00, 0x00}, false, 0},
+       {[]byte{}, false, 0},
+       {[]byte{0x00, 0x7f}, false, 0},
+       {[]byte{0xff, 0xf0}, false, 0},
 }
 
 func TestParseInt32(t *testing.T) {
@@ -104,27 +108,36 @@ func TestParseInt32(t *testing.T) {
 
 var bigIntTests = []struct {
        in     []byte
+       ok     bool
        base10 string
 }{
-       {[]byte{0xff}, "-1"},
-       {[]byte{0x00}, "0"},
-       {[]byte{0x01}, "1"},
-       {[]byte{0x00, 0xff}, "255"},
-       {[]byte{0xff, 0x00}, "-256"},
-       {[]byte{0x01, 0x00}, "256"},
+       {[]byte{0xff}, true, "-1"},
+       {[]byte{0x00}, true, "0"},
+       {[]byte{0x01}, true, "1"},
+       {[]byte{0x00, 0xff}, true, "255"},
+       {[]byte{0xff, 0x00}, true, "-256"},
+       {[]byte{0x01, 0x00}, true, "256"},
+       {[]byte{}, false, ""},
+       {[]byte{0x00, 0x7f}, false, ""},
+       {[]byte{0xff, 0xf0}, false, ""},
 }
 
 func TestParseBigInt(t *testing.T) {
        for i, test := range bigIntTests {
-               ret := parseBigInt(test.in)
-               if ret.String() != test.base10 {
-                       t.Errorf("#%d: bad result from %x, got %s want %s", i, test.in, ret.String(), test.base10)
+               ret, err := parseBigInt(test.in)
+               if (err == nil) != test.ok {
+                       t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
                }
-               fw := newForkableWriter()
-               marshalBigInt(fw, ret)
-               result := fw.Bytes()
-               if !bytes.Equal(result, test.in) {
-                       t.Errorf("#%d: got %x from marshaling %s, want %x", i, result, ret, test.in)
+               if test.ok {
+                       if ret.String() != test.base10 {
+                               t.Errorf("#%d: bad result from %x, got %s want %s", i, test.in, ret.String(), test.base10)
+                       }
+                       fw := newForkableWriter()
+                       marshalBigInt(fw, ret)
+                       result := fw.Bytes()
+                       if !bytes.Equal(result, test.in) {
+                               t.Errorf("#%d: got %x from marshaling %s, want %x", i, result, ret, test.in)
+                       }
                }
        }
 }
@@ -354,17 +367,21 @@ var tagAndLengthData = []tagAndLengthTest{
        {[]byte{0x1f, 0x01, 0x00}, true, tagAndLength{0, 1, 0, false}},
        {[]byte{0x1f, 0x81, 0x00, 0x00}, true, tagAndLength{0, 128, 0, false}},
        {[]byte{0x1f, 0x81, 0x80, 0x01, 0x00}, true, tagAndLength{0, 0x4001, 0, false}},
-       {[]byte{0x00, 0x81, 0x01}, true, tagAndLength{0, 0, 1, false}},
+       {[]byte{0x00, 0x81, 0x80}, true, tagAndLength{0, 0, 128, false}},
        {[]byte{0x00, 0x82, 0x01, 0x00}, true, tagAndLength{0, 0, 256, false}},
        {[]byte{0x00, 0x83, 0x01, 0x00}, false, tagAndLength{}},
        {[]byte{0x1f, 0x85}, false, tagAndLength{}},
        {[]byte{0x30, 0x80}, false, tagAndLength{}},
        // Superfluous zeros in the length should be an error.
-       {[]byte{0xa0, 0x82, 0x00, 0x01}, false, tagAndLength{}},
+       {[]byte{0xa0, 0x82, 0x00, 0xff}, false, tagAndLength{}},
        // Lengths up to the maximum size of an int should work.
        {[]byte{0xa0, 0x84, 0x7f, 0xff, 0xff, 0xff}, true, tagAndLength{2, 0, 0x7fffffff, true}},
        // Lengths that would overflow an int should be rejected.
        {[]byte{0xa0, 0x84, 0x80, 0x00, 0x00, 0x00}, false, tagAndLength{}},
+       // Long length form may not be used for lengths that fit in short form.
+       {[]byte{0xa0, 0x81, 0x7f}, false, tagAndLength{}},
+       // Tag numbers which would overflow int32 are rejected. (The value below is 2^31.)
+       {[]byte{0x1f, 0x88, 0x80, 0x80, 0x80, 0x00, 0x00}, false, tagAndLength{}},
 }
 
 func TestParseTagAndLength(t *testing.T) {
@@ -394,10 +411,10 @@ func newBool(b bool) *bool { return &b }
 
 var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParametersTest{
        {"", fieldParameters{}},
-       {"ia5", fieldParameters{stringType: tagIA5String}},
-       {"generalized", fieldParameters{timeType: tagGeneralizedTime}},
-       {"utc", fieldParameters{timeType: tagUTCTime}},
-       {"printable", fieldParameters{stringType: tagPrintableString}},
+       {"ia5", fieldParameters{stringType: TagIA5String}},
+       {"generalized", fieldParameters{timeType: TagGeneralizedTime}},
+       {"utc", fieldParameters{timeType: TagUTCTime}},
+       {"printable", fieldParameters{stringType: TagPrintableString}},
        {"optional", fieldParameters{optional: true}},
        {"explicit", fieldParameters{explicit: true, tag: new(int)}},
        {"application", fieldParameters{application: true, tag: new(int)}},
@@ -940,3 +957,15 @@ func TestUnmarshalInvalidUTF8(t *testing.T) {
                t.Fatalf("Expected error to mention %q but error was %q", expectedSubstring, err.Error())
        }
 }
+
+func TestMarshalNilValue(t *testing.T) {
+       nilValueTestData := []interface{}{
+               nil,
+               struct{ v interface{} }{},
+       }
+       for i, test := range nilValueTestData {
+               if _, err := Marshal(test); err == nil {
+                       t.Fatalf("#%d: successfully marshaled nil value", i)
+               }
+       }
+}
index ab85e0496ff85171ee05f531eb4559c3694be7c7..069518082772b3fd6cc94272104096e3c7438874 100644 (file)
@@ -18,29 +18,31 @@ import (
 
 // Here are some standard tags and classes
 
+// ASN.1 tags represent the type of the following object.
 const (
-       tagBoolean         = 1
-       tagInteger         = 2
-       tagBitString       = 3
-       tagOctetString     = 4
-       tagOID             = 6
-       tagEnum            = 10
-       tagUTF8String      = 12
-       tagSequence        = 16
-       tagSet             = 17
-       tagPrintableString = 19
-       tagT61String       = 20
-       tagIA5String       = 22
-       tagUTCTime         = 23
-       tagGeneralizedTime = 24
-       tagGeneralString   = 27
+       TagBoolean         = 1
+       TagInteger         = 2
+       TagBitString       = 3
+       TagOctetString     = 4
+       TagOID             = 6
+       TagEnum            = 10
+       TagUTF8String      = 12
+       TagSequence        = 16
+       TagSet             = 17
+       TagPrintableString = 19
+       TagT61String       = 20
+       TagIA5String       = 22
+       TagUTCTime         = 23
+       TagGeneralizedTime = 24
+       TagGeneralString   = 27
 )
 
+// ASN.1 class types represent the namespace of the tag.
 const (
-       classUniversal       = 0
-       classApplication     = 1
-       classContextSpecific = 2
-       classPrivate         = 3
+       ClassUniversal       = 0
+       ClassApplication     = 1
+       ClassContextSpecific = 2
+       ClassPrivate         = 3
 )
 
 type tagAndLength struct {
@@ -96,15 +98,15 @@ func parseFieldParameters(str string) (ret fieldParameters) {
                                ret.tag = new(int)
                        }
                case part == "generalized":
-                       ret.timeType = tagGeneralizedTime
+                       ret.timeType = TagGeneralizedTime
                case part == "utc":
-                       ret.timeType = tagUTCTime
+                       ret.timeType = TagUTCTime
                case part == "ia5":
-                       ret.stringType = tagIA5String
+                       ret.stringType = TagIA5String
                case part == "printable":
-                       ret.stringType = tagPrintableString
+                       ret.stringType = TagPrintableString
                case part == "utf8":
-                       ret.stringType = tagUTF8String
+                       ret.stringType = TagUTF8String
                case strings.HasPrefix(part, "default:"):
                        i, err := strconv.ParseInt(part[8:], 10, 64)
                        if err == nil {
@@ -136,33 +138,33 @@ func parseFieldParameters(str string) (ret fieldParameters) {
 func getUniversalType(t reflect.Type) (tagNumber int, isCompound, ok bool) {
        switch t {
        case objectIdentifierType:
-               return tagOID, false, true
+               return TagOID, false, true
        case bitStringType:
-               return tagBitString, false, true
+               return TagBitString, false, true
        case timeType:
-               return tagUTCTime, false, true
+               return TagUTCTime, false, true
        case enumeratedType:
-               return tagEnum, false, true
+               return TagEnum, false, true
        case bigIntType:
-               return tagInteger, false, true
+               return TagInteger, false, true
        }
        switch t.Kind() {
        case reflect.Bool:
-               return tagBoolean, false, true
+               return TagBoolean, false, true
        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-               return tagInteger, false, true
+               return TagInteger, false, true
        case reflect.Struct:
-               return tagSequence, true, true
+               return TagSequence, true, true
        case reflect.Slice:
                if t.Elem().Kind() == reflect.Uint8 {
-                       return tagOctetString, false, true
+                       return TagOctetString, false, true
                }
                if strings.HasSuffix(t.Name(), "SET") {
-                       return tagSet, true, true
+                       return TagSet, true, true
                }
-               return tagSequence, true, true
+               return TagSequence, true, true
        case reflect.String:
-               return tagPrintableString, false, true
+               return TagPrintableString, false, true
        }
        return 0, false, false
 }
index 67a019db2d40677d68517e2d44330419f12e743b..6e858584a67f90d43547153ffa919336d66f3919 100644 (file)
@@ -414,7 +414,7 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter
                return nil
        case timeType:
                t := value.Interface().(time.Time)
-               if params.timeType == tagGeneralizedTime || outsideUTCRange(t) {
+               if params.timeType == TagGeneralizedTime || outsideUTCRange(t) {
                        return marshalGeneralizedTime(out, t)
                } else {
                        return marshalUTCTime(out, t)
@@ -493,9 +493,9 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter
                return
        case reflect.String:
                switch params.stringType {
-               case tagIA5String:
+               case TagIA5String:
                        return marshalIA5String(out, v.String())
-               case tagPrintableString:
+               case TagPrintableString:
                        return marshalPrintableString(out, v.String())
                default:
                        return marshalUTF8String(out, v.String())
@@ -506,6 +506,9 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter
 }
 
 func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) (err error) {
+       if !v.IsValid() {
+               return fmt.Errorf("asn1: cannot marshal nil value")
+       }
        // If the field is an interface{} then recurse into it.
        if v.Kind() == reflect.Interface && v.Type().NumMethod() == 0 {
                return marshalField(out, v.Elem(), params)
@@ -552,18 +555,18 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
                err = StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type())}
                return
        }
-       class := classUniversal
+       class := ClassUniversal
 
-       if params.timeType != 0 && tag != tagUTCTime {
+       if params.timeType != 0 && tag != TagUTCTime {
                return StructuralError{"explicit time type given to non-time member"}
        }
 
-       if params.stringType != 0 && tag != tagPrintableString {
+       if params.stringType != 0 && tag != TagPrintableString {
                return StructuralError{"explicit string type given to non-string member"}
        }
 
        switch tag {
-       case tagPrintableString:
+       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
@@ -573,24 +576,24 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
                                        if !utf8.ValidString(v.String()) {
                                                return errors.New("asn1: string not valid UTF-8")
                                        }
-                                       tag = tagUTF8String
+                                       tag = TagUTF8String
                                        break
                                }
                        }
                } else {
                        tag = params.stringType
                }
-       case tagUTCTime:
-               if params.timeType == tagGeneralizedTime || outsideUTCRange(v.Interface().(time.Time)) {
-                       tag = tagGeneralizedTime
+       case TagUTCTime:
+               if params.timeType == TagGeneralizedTime || outsideUTCRange(v.Interface().(time.Time)) {
+                       tag = TagGeneralizedTime
                }
        }
 
        if params.set {
-               if tag != tagSequence {
+               if tag != TagSequence {
                        return StructuralError{"non sequence tagged as set"}
                }
-               tag = tagSet
+               tag = TagSet
        }
 
        tags, body := out.fork()
@@ -610,7 +613,7 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
        if !params.explicit && params.tag != nil {
                // implicit tag.
                tag = *params.tag
-               class = classContextSpecific
+               class = ClassContextSpecific
        }
 
        err = marshalTagAndLength(tags, tagAndLength{class, tag, bodyLen, isCompound})
@@ -620,14 +623,14 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
 
        if params.explicit {
                err = marshalTagAndLength(explicitTag, tagAndLength{
-                       class:      classContextSpecific,
+                       class:      ClassContextSpecific,
                        tag:        *params.tag,
                        length:     bodyLen + tags.Len(),
                        isCompound: true,
                })
        }
 
-       return nil
+       return err
 }
 
 // Marshal returns the ASN.1 encoding of val.
@@ -648,5 +651,5 @@ func Marshal(val interface{}) ([]byte, error) {
                return nil, err
        }
        _, err = f.writeTo(&out)
-       return out.Bytes(), nil
+       return out.Bytes(), err
 }
index 3302fb4a7426924d2f9b6f529184193f5bb19df9..1bda804c38ab4868e91d240c1245a78e35e73412 100644 (file)
@@ -75,7 +75,7 @@ var URLEncoding = NewEncoding(encodeURL)
 // This is the same as StdEncoding but omits padding characters.
 var RawStdEncoding = StdEncoding.WithPadding(NoPadding)
 
-// URLEncoding is the unpadded alternate base64 encoding defined in RFC 4648.
+// RawURLEncoding is the unpadded alternate base64 encoding defined in RFC 4648.
 // It is typically used in URLs and file names.
 // This is the same as URLEncoding but omits padding characters.
 var RawURLEncoding = URLEncoding.WithPadding(NoPadding)
@@ -346,21 +346,18 @@ func (enc *Encoding) DecodeString(s string) ([]byte, error) {
 }
 
 type decoder struct {
-       err    error
-       enc    *Encoding
-       r      io.Reader
-       end    bool       // saw end of message
-       buf    [1024]byte // leftover input
-       nbuf   int
-       out    []byte // leftover decoded output
-       outbuf [1024 / 4 * 3]byte
+       err     error
+       readErr error // error from r.Read
+       enc     *Encoding
+       r       io.Reader
+       end     bool       // saw end of message
+       buf     [1024]byte // leftover input
+       nbuf    int
+       out     []byte // leftover decoded output
+       outbuf  [1024 / 4 * 3]byte
 }
 
 func (d *decoder) Read(p []byte) (n int, err error) {
-       if d.err != nil {
-               return 0, d.err
-       }
-
        // Use leftover decoded output from last read.
        if len(d.out) > 0 {
                n = copy(p, d.out)
@@ -368,19 +365,46 @@ func (d *decoder) Read(p []byte) (n int, err error) {
                return n, nil
        }
 
+       if d.err != nil {
+               return 0, d.err
+       }
+
        // This code assumes that d.r strips supported whitespace ('\r' and '\n').
 
-       // Read a chunk.
-       nn := len(p) / 3 * 4
-       if nn < 4 {
-               nn = 4
-       }
-       if nn > len(d.buf) {
-               nn = len(d.buf)
+       // Refill buffer.
+       for d.nbuf < 4 && d.readErr == nil {
+               nn := len(p) / 3 * 4
+               if nn < 4 {
+                       nn = 4
+               }
+               if nn > len(d.buf) {
+                       nn = len(d.buf)
+               }
+               nn, d.readErr = d.r.Read(d.buf[d.nbuf:nn])
+               d.nbuf += nn
        }
-       nn, d.err = io.ReadAtLeast(d.r, d.buf[d.nbuf:nn], 4-d.nbuf)
-       d.nbuf += nn
-       if d.err != nil || d.nbuf < 4 {
+
+       if d.nbuf < 4 {
+               if d.enc.padChar == NoPadding && d.nbuf > 0 {
+                       // Decode final fragment, without padding.
+                       var nw int
+                       nw, _, d.err = d.enc.decode(d.outbuf[:], d.buf[:d.nbuf])
+                       d.nbuf = 0
+                       d.end = true
+                       d.out = d.outbuf[:nw]
+                       n = copy(p, d.out)
+                       d.out = d.out[n:]
+                       if n > 0 || len(p) == 0 && len(d.out) > 0 {
+                               return n, nil
+                       }
+                       if d.err != nil {
+                               return 0, d.err
+                       }
+               }
+               d.err = d.readErr
+               if d.err == io.EOF && d.nbuf > 0 {
+                       d.err = io.ErrUnexpectedEOF
+               }
                return 0, d.err
        }
 
@@ -396,13 +420,7 @@ func (d *decoder) Read(p []byte) (n int, err error) {
                n, d.end, d.err = d.enc.decode(p, d.buf[:nr])
        }
        d.nbuf -= nr
-       for i := 0; i < d.nbuf; i++ {
-               d.buf[i] = d.buf[i+nr]
-       }
-
-       if d.err == nil {
-               d.err = err
-       }
+       copy(d.buf[:d.nbuf], d.buf[nr:])
        return n, d.err
 }
 
index d144b96821f9bf614e5f1e3ec2a9a0ddc9d144be..fc6a1ea654f75cae6721a366af336dd80f54f105 100644 (file)
@@ -80,11 +80,11 @@ type encodingTest struct {
 }
 
 var encodingTests = []encodingTest{
-       encodingTest{StdEncoding, stdRef},
-       encodingTest{URLEncoding, urlRef},
-       encodingTest{RawStdEncoding, rawRef},
-       encodingTest{RawURLEncoding, rawUrlRef},
-       encodingTest{funnyEncoding, funnyRef},
+       {StdEncoding, stdRef},
+       {URLEncoding, urlRef},
+       {RawStdEncoding, rawRef},
+       {RawURLEncoding, rawUrlRef},
+       {funnyEncoding, funnyRef},
 }
 
 var bigtest = testpair{
@@ -406,3 +406,28 @@ func BenchmarkDecodeString(b *testing.B) {
                StdEncoding.DecodeString(data)
        }
 }
+
+func TestDecoderRaw(t *testing.T) {
+       source := "AAAAAA"
+       want := []byte{0, 0, 0, 0}
+
+       // Direct.
+       dec1, err := RawURLEncoding.DecodeString(source)
+       if err != nil || !bytes.Equal(dec1, want) {
+               t.Errorf("RawURLEncoding.DecodeString(%q) = %x, %v, want %x, nil", source, dec1, err, want)
+       }
+
+       // Through reader. Used to fail.
+       r := NewDecoder(RawURLEncoding, bytes.NewReader([]byte(source)))
+       dec2, err := ioutil.ReadAll(io.LimitReader(r, 100))
+       if err != nil || !bytes.Equal(dec2, want) {
+               t.Errorf("reading NewDecoder(RawURLEncoding, %q) = %x, %v, want %x, nil", source, dec2, err, want)
+       }
+
+       // Should work with padding.
+       r = NewDecoder(URLEncoding, bytes.NewReader([]byte(source+"==")))
+       dec3, err := ioutil.ReadAll(r)
+       if err != nil || !bytes.Equal(dec3, want) {
+               t.Errorf("reading NewDecoder(URLEncoding, %q) = %x, %v, want %x, nil", source+"==", dec3, err, want)
+       }
+}
index 2bbe07c02ff3153886c76f8756ca9c83a3bfbfe0..1c2577b68decdeafe4dacf4c134e03add1ab00c9 100644 (file)
@@ -135,6 +135,10 @@ func (bigEndian) GoString() string { return "binary.BigEndian" }
 // 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.
+//
+// The error is EOF only if no bytes were read.
+// If an EOF happens after reading some but not all the bytes,
+// Read returns ErrUnexpectedEOF.
 func Read(r io.Reader, order ByteOrder, data interface{}) error {
        // Fast path for basic types and slices.
        if n := intDataSize(data); n != 0 {
index 8ee595fa476aabb677c87b08a065aec30b90af8c..7fd36fa4efa9bc3b7e886349a428add945d12e9e 100644 (file)
@@ -309,6 +309,36 @@ func TestReadErrorMsg(t *testing.T) {
        read(&p)
 }
 
+func TestReadTruncated(t *testing.T) {
+       const data = "0123456789abcdef"
+
+       var b1 = make([]int32, 4)
+       var b2 struct {
+               A, B, C, D byte
+               E          int32
+               F          float64
+       }
+
+       for i := 0; i <= len(data); i++ {
+               var errWant error
+               switch i {
+               case 0:
+                       errWant = io.EOF
+               case len(data):
+                       errWant = nil
+               default:
+                       errWant = io.ErrUnexpectedEOF
+               }
+
+               if err := Read(strings.NewReader(data[:i]), LittleEndian, &b1); err != errWant {
+                       t.Errorf("Read(%d) with slice: got %v, want %v", i, err, errWant)
+               }
+               if err := Read(strings.NewReader(data[:i]), LittleEndian, &b2); err != errWant {
+                       t.Errorf("Read(%d) with struct: got %v, want %v", i, err, errWant)
+               }
+       }
+}
+
 type byteSliceReader struct {
        remain []byte
 }
index 37bf80ceaedd9b8e7e69fe5a3d852a5d5b6dd787..a6bb780bf28a0b76de6fd02e323665d1db8cd5fc 100644 (file)
@@ -155,7 +155,7 @@ func (r *Reader) Read() (record []string, err error) {
 
 // ReadAll reads all the remaining records from r.
 // Each record is a slice of fields.
-// A successful call returns err == nil, not err == EOF. Because ReadAll is
+// A successful call returns err == nil, not err == io.EOF. Because ReadAll is
 // defined to read until EOF, it does not treat end of file as an error to be
 // reported.
 func (r *Reader) ReadAll() (records [][]string, err error) {
index c2583bfee337d18fbe4971dbbff005419805b5c8..8efcdc78fff1e6cd422ae426f554e645574e4aae 100644 (file)
@@ -88,7 +88,6 @@ func verifyInt(i int64, t *testing.T) {
        encState := newEncoderState(b)
        encState.encodeInt(i)
        decState := newDecodeState(newDecBuffer(b.Bytes()))
-       decState.buf = make([]byte, 8)
        j := decState.decodeInt()
        if i != j {
                t.Errorf("Encode/Decode: sent %#x received %#x", uint64(i), uint64(j))
@@ -127,7 +126,6 @@ var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'}
 func newDecodeState(buf *decBuffer) *decoderState {
        d := new(decoderState)
        d.b = buf
-       d.buf = make([]byte, uint64Size)
        return d
 }
 
@@ -1488,7 +1486,7 @@ func TestErrorInvalidTypeId(t *testing.T) {
                var foo struct{}
                err := d.Decode(&foo)
                if err != errBadType {
-                       t.Fatal("decode: expected %s, got %s", errBadType, err)
+                       t.Fatalf("decode: expected %s, got %s", errBadType, err)
                }
        }
 }
index a1b67661d8f5f1f959ee358a8192d0c0ef712301..3aa038da75eb8ce9a3fafe18d7f622fac7df6ca7 100644 (file)
@@ -327,11 +327,12 @@ func decStringSlice(state *decoderState, v reflect.Value, length int, ovfl error
                        errorf("string data too long for buffer: %d", n)
                }
                // Read the data.
-               data := make([]byte, n)
-               if _, err := state.b.Read(data); err != nil {
-                       errorf("error decoding string: %s", err)
+               data := state.b.Bytes()
+               if len(data) < n {
+                       errorf("invalid string length %d: exceeds input size %d", n, len(data))
                }
-               slice[i] = string(data)
+               slice[i] = string(data[:n])
+               state.b.Drop(n)
        }
        return true
 }
index da41a899ed01ca8d57f7827648b0ae376719f20b..ef73f2dc4a012c410a01b16781ac9a833bf59fae 100644 (file)
@@ -112,11 +112,12 @@ var types = []Type{
                        errorf("string data too long for buffer: %d", n)
                }
                // Read the data.
-               data := make([]byte, n)
-               if _, err := state.b.Read(data); err != nil {
-                       errorf("error decoding string: %s", err)
+               data := state.b.Bytes()
+               if len(data) < n {
+                       errorf("invalid string length %d: exceeds input size %d", n, len(data))
                }
-               slice[i] = string(data)`,
+               slice[i] = string(data[:n])
+               state.b.Drop(n)`,
        },
        {
                "uint",
index e913f15c545a240cc0760cd681fcc10af9664653..3b0dca86f349f091bfa0cac0eb332a5d3c18417a 100644 (file)
@@ -29,8 +29,7 @@ type decoderState struct {
        // The buffer is stored with an extra indirection because it may be replaced
        // if we load a type during decode (when reading an interface value).
        b        *decBuffer
-       fieldnum int // the last field number read.
-       buf      []byte
+       fieldnum int           // the last field number read.
        next     *decoderState // for free list
 }
 
@@ -97,7 +96,6 @@ func (dec *Decoder) newDecoderState(buf *decBuffer) *decoderState {
        if d == nil {
                d = new(decoderState)
                d.dec = dec
-               d.buf = make([]byte, uint64Size)
        } else {
                dec.freeList = d.next
        }
@@ -160,15 +158,16 @@ func (state *decoderState) decodeUint() (x uint64) {
        if n > uint64Size {
                error_(errBadUint)
        }
-       width, err := state.b.Read(state.buf[0:n])
-       if err != nil {
-               error_(err)
+       buf := state.b.Bytes()
+       if len(buf) < n {
+               errorf("invalid uint data length %d: exceeds input size %d", n, len(buf))
        }
        // Don't need to check error; it's safe to loop regardless.
        // Could check that the high byte is zero but it's not worth it.
-       for _, b := range state.buf[0:width] {
+       for _, b := range buf[0:n] {
                x = x<<8 | uint64(b)
        }
+       state.b.Drop(n)
        return x
 }
 
@@ -397,11 +396,13 @@ func decString(i *decInstr, state *decoderState, value reflect.Value) {
                errorf("bad %s slice length: %d", value.Type(), n)
        }
        // Read the data.
-       data := make([]byte, n)
-       if _, err := state.b.Read(data); err != nil {
-               errorf("error decoding string: %s", err)
+       data := state.b.Bytes()
+       if len(data) < n {
+               errorf("invalid string length %d: exceeds input size %d", n, len(data))
        }
-       value.SetString(string(data))
+       s := string(data[:n])
+       state.b.Drop(n)
+       value.SetString(s)
 }
 
 // ignoreUint8Array skips over the data for a byte slice value with no destination.
@@ -410,8 +411,11 @@ func ignoreUint8Array(i *decInstr, state *decoderState, value reflect.Value) {
        if !ok {
                errorf("slice length too large")
        }
-       b := make([]byte, n)
-       state.b.Read(b)
+       bn := state.b.Len()
+       if bn < n {
+               errorf("invalid slice length %d: exceeds input size %d", n, bn)
+       }
+       state.b.Drop(n)
 }
 
 // Execution engine
@@ -634,15 +638,15 @@ func (dec *Decoder) ignoreSlice(state *decoderState, elemOp decOp) {
 func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, value reflect.Value) {
        // Read the name of the concrete type.
        nr := state.decodeUint()
-       if nr < 0 || nr > 1<<31 { // zero is permissible for anonymous types
+       if nr > 1<<31 { // zero is permissible for anonymous types
                errorf("invalid type name length %d", nr)
        }
        if nr > uint64(state.b.Len()) {
                errorf("invalid type name length %d: exceeds input size", nr)
        }
-       b := make([]byte, nr)
-       state.b.Read(b)
-       name := string(b)
+       n := int(nr)
+       name := string(state.b.Bytes()[:n])
+       state.b.Drop(n)
        // Allocate the destination interface value.
        if name == "" {
                // Copy the nil interface value to the target.
@@ -689,11 +693,11 @@ func (dec *Decoder) ignoreInterface(state *decoderState) {
        if !ok {
                errorf("bad interface encoding: name too large for buffer")
        }
-       b := make([]byte, n)
-       _, err := state.b.Read(b)
-       if err != nil {
-               error_(err)
+       bn := state.b.Len()
+       if bn < n {
+               errorf("invalid interface value length %d: exceeds input size %d", n, bn)
        }
+       state.b.Drop(n)
        id := dec.decodeTypeSequence(true)
        if id < 0 {
                error_(dec.err)
@@ -714,11 +718,13 @@ func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, valu
        if !ok {
                errorf("GobDecoder: length too large for buffer")
        }
-       b := make([]byte, n)
-       _, err := state.b.Read(b)
-       if err != nil {
-               error_(err)
+       b := state.b.Bytes()
+       if len(b) < n {
+               errorf("GobDecoder: invalid data length %d: exceeds input size %d", n, len(b))
        }
+       b = b[:n]
+       state.b.Drop(n)
+       var err error
        // We know it's one of these.
        switch ut.externalDec {
        case xGob:
@@ -740,11 +746,11 @@ func (dec *Decoder) ignoreGobDecoder(state *decoderState) {
        if !ok {
                errorf("GobDecoder: length too large for buffer")
        }
-       b := make([]byte, n)
-       _, err := state.b.Read(b)
-       if err != nil {
-               error_(err)
+       bn := state.b.Len()
+       if bn < n {
+               errorf("GobDecoder: invalid data length %d: exceeds input size %d", n, bn)
        }
+       state.b.Drop(n)
 }
 
 // Index by Go types.
index 4d3d0076fbc570a32ef7cdb83ae7d12b15a3bc5f..cf878f450295f4d3ff8c62ed869ee32adbc576bb 100644 (file)
@@ -82,6 +82,12 @@ slice has capacity the slice will be extended in place; if not, a new array is
 allocated. Regardless, the length of the resulting slice reports the number of
 elements decoded.
 
+In general, if allocation is required, the decoder will allocate memory. If not,
+it will update the destination variables with values read from the stream. It does
+not initialize them first, so if the destination is a compound value such as a
+map, struct, or slice, the decoded values will be merged elementwise into the
+existing variables.
+
 Functions and channels will not be sent in a gob. Attempting to encode such a value
 at the top level will fail. A struct field of chan or func type is treated exactly
 like an unexported field and is ignored.
@@ -141,18 +147,21 @@ pairs. Empty but non-nil maps are sent, so if the receiver has not allocated
 one already, one will always be allocated on receipt unless the transmitted map
 is nil and not at the top level.
 
+In slices and arrays, as well as maps, all elements, even zero-valued elements,
+are transmitted, even if all the elements are zero.
+
 Structs are sent as a sequence of (field number, field value) pairs.  The field
 value is sent using the standard gob encoding for its type, recursively.  If a
-field has the zero value for its type, it is omitted from the transmission.  The
-field number is defined by the type of the encoded struct: the first field of the
-encoded type is field 0, the second is field 1, etc.  When encoding a value, the
-field numbers are delta encoded for efficiency and the fields are always sent in
-order of increasing field number; the deltas are therefore unsigned.  The
-initialization for the delta encoding sets the field number to -1, so an unsigned
-integer field 0 with value 7 is transmitted as unsigned delta = 1, unsigned value
-= 7 or (01 07).  Finally, after all the fields have been sent a terminating mark
-denotes the end of the struct.  That mark is a delta=0 value, which has
-representation (00).
+field has the zero value for its type (except for arrays; see above), it is omitted
+from the transmission.  The field number is defined by the type of the encoded
+struct: the first field of the encoded type is field 0, the second is field 1,
+etc.  When encoding a value, the field numbers are delta encoded for efficiency
+and the fields are always sent in order of increasing field number; the deltas are
+therefore unsigned.  The initialization for the delta encoding sets the field
+number to -1, so an unsigned integer field 0 with value 7 is transmitted as unsigned
+delta = 1, unsigned value = 7 or (01 07).  Finally, after all the fields have been
+sent a terminating mark denotes the end of the struct.  That mark is a delta=0
+value, which has representation (00).
 
 Interface types are not checked for compatibility; all interface types are
 treated, for transmission, as members of a single "interface" type, analogous to
index f66279f14134b505825c803f15483e89816493e9..96052ef33b6f07b99e1a1fe6779950e7e654ff42 100644 (file)
@@ -10,6 +10,7 @@ import (
        "encoding"
        "math"
        "reflect"
+       "sync"
 )
 
 const uint64Size = 8
@@ -36,6 +37,14 @@ type encBuffer struct {
        scratch [64]byte
 }
 
+var encBufferPool = sync.Pool{
+       New: func() interface{} {
+               e := new(encBuffer)
+               e.data = e.scratch[0:0]
+               return e
+       },
+}
+
 func (e *encBuffer) WriteByte(c byte) {
        e.data = append(e.data, c)
 }
@@ -58,7 +67,11 @@ func (e *encBuffer) Bytes() []byte {
 }
 
 func (e *encBuffer) Reset() {
-       e.data = e.data[0:0]
+       if len(e.data) >= tooBig {
+               e.data = e.scratch[0:0]
+       } else {
+               e.data = e.data[0:0]
+       }
 }
 
 func (enc *Encoder) newEncoderState(b *encBuffer) *encoderState {
@@ -407,7 +420,7 @@ func (enc *Encoder) encodeInterface(b *encBuffer, iv reflect.Value) {
        // Encode the value into a new buffer.  Any nested type definitions
        // should be written to b, before the encoded value.
        enc.pushWriter(b)
-       data := new(encBuffer)
+       data := encBufferPool.Get().(*encBuffer)
        data.Write(spaceForLength)
        enc.encode(data, elem, ut)
        if enc.err != nil {
@@ -415,6 +428,8 @@ func (enc *Encoder) encodeInterface(b *encBuffer, iv reflect.Value) {
        }
        enc.popWriter()
        enc.writeMessage(b, data)
+       data.Reset()
+       encBufferPool.Put(data)
        if enc.err != nil {
                error_(enc.err)
        }
index dc657348223ce005dc3055ea9d68da918a3697fc..570d79696bb76f62d7a611b2c10a9ec6cd6582da 100644 (file)
@@ -978,7 +978,7 @@ var badDataTests = []badDataTest{
        {"0f1000fb285d003316020735ff023a65c5", "interface encoding", nil},
        {"03fffb0616fffc00f902ff02ff03bf005d02885802a311a8120228022c028ee7", "GobDecoder", nil},
        // Issue 10491.
-       {"10fe010f020102fe01100001fe010e000016fe010d030102fe010e00010101015801fe01100000000bfe011000f85555555555555555", "length exceeds input size", nil},
+       {"10fe010f020102fe01100001fe010e000016fe010d030102fe010e00010101015801fe01100000000bfe011000f85555555555555555", "exceeds input size", nil},
 }
 
 // TestBadData tests that various problems caused by malformed input
index 940e5ad4126a7f025de32624d62eede74759548b..424b7e6ea8e7a2b91dd3f105f7bb39cc9ceaaf16 100644 (file)
@@ -127,8 +127,8 @@ func TestCountDecodeMallocs(t *testing.T) {
                        t.Fatal("decode:", err)
                }
        })
-       if allocs != 4 {
-               t.Fatalf("mallocs per decode of type Bench: %v; wanted 4\n", allocs)
+       if allocs != 3 {
+               t.Fatalf("mallocs per decode of type Bench: %v; wanted 3\n", allocs)
        }
 }
 
@@ -200,6 +200,23 @@ func BenchmarkEncodeStringSlice(b *testing.B) {
        }
 }
 
+func BenchmarkEncodeInterfaceSlice(b *testing.B) {
+       var buf bytes.Buffer
+       enc := NewEncoder(&buf)
+       a := make([]interface{}, 1000)
+       for i := range a {
+               a[i] = "now is the time"
+       }
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               buf.Reset()
+               err := enc.Encode(a)
+               if err != nil {
+                       b.Fatal(err)
+               }
+       }
+}
+
 // benchmarkBuf is a read buffer we can reset
 type benchmarkBuf struct {
        offset int
@@ -323,3 +340,27 @@ func BenchmarkDecodeStringSlice(b *testing.B) {
                }
        }
 }
+
+func BenchmarkDecodeInterfaceSlice(b *testing.B) {
+       var buf bytes.Buffer
+       enc := NewEncoder(&buf)
+       a := make([]interface{}, 1000)
+       for i := range a {
+               a[i] = "now is the time"
+       }
+       err := enc.Encode(a)
+       if err != nil {
+               b.Fatal(err)
+       }
+       x := make([]interface{}, 1000)
+       bbuf := benchmarkBuf{data: buf.Bytes()}
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               bbuf.reset()
+               dec := NewDecoder(&bbuf)
+               err := dec.Decode(&x)
+               if err != nil {
+                       b.Fatal(i, err)
+               }
+       }
+}
index a49b71a8676786c67aa38dbae07c8ddbdbd86ec6..cf5cec0703bcc0f1cbeed1664e4bea00bdf6cb0a 100644 (file)
@@ -787,7 +787,7 @@ func mustGetTypeInfo(rt reflect.Type) *typeInfo {
 // contain things such as private fields, channels, and functions,
 // which are not usually transmissible in gob streams.
 //
-// Note: Since gobs can be stored permanently, It is good design
+// Note: Since gobs can be stored permanently, it is good design
 // to guarantee the encoding used by a GobEncoder is stable as the
 // software evolves.  For instance, it might make sense for GobEncode
 // to include a version number in the encoding.
index 530e8521dc5e6eccecfd0cde8926edada7d793fe..539d952ad68678974ebb1cab0845e5db67998a56 100644 (file)
@@ -37,6 +37,7 @@ import (
 // To unmarshal JSON into a struct, Unmarshal matches incoming object
 // keys to the keys used by Marshal (either the struct field name or its tag),
 // preferring an exact match but also accepting a case-insensitive match.
+// Unmarshal will only set exported fields of the struct.
 //
 // To unmarshal JSON into an interface value,
 // Unmarshal stores one of these in the interface value:
@@ -48,16 +49,26 @@ import (
 //     map[string]interface{}, for JSON objects
 //     nil for JSON null
 //
-// To unmarshal a JSON array into a slice, Unmarshal resets the slice to nil
-// and then appends each element to the slice.
+// To unmarshal a JSON array into a slice, Unmarshal resets the slice length
+// to zero and then appends each element to the slice.
+// As a special case, to unmarshal an empty JSON array into a slice,
+// Unmarshal replaces the slice with a new empty slice.
 //
-// To unmarshal a JSON object into a map, Unmarshal replaces the map
-// with an empty map and then adds key-value pairs from the object to
-// the map.
+// To unmarshal a JSON array into a Go array, Unmarshal decodes
+// JSON array elements into corresponding Go array elements.
+// If the Go array is smaller than the JSON array,
+// the additional JSON array elements are discarded.
+// If the JSON array is smaller than the Go array,
+// the additional Go array elements are set to zero values.
+//
+// To unmarshal a JSON object into a string-keyed map, Unmarshal first
+// establishes a map to use, If the map is nil, Unmarshal allocates a new map.
+// Otherwise Unmarshal reuses the existing map, keeping existing entries.
+// Unmarshal then stores key-value pairs from the JSON object into the map.
 //
 // If a JSON value is not appropriate for a given target type,
 // or if a JSON number overflows the target type, Unmarshal
-// skips that field and completes the unmarshalling as best it can.
+// skips that field and completes the unmarshaling as best it can.
 // If no more serious errors are encountered, Unmarshal returns
 // an UnmarshalTypeError describing the earliest such error.
 //
@@ -174,6 +185,66 @@ func (n Number) Int64() (int64, error) {
        return strconv.ParseInt(string(n), 10, 64)
 }
 
+// isValidNumber reports whether s is a valid JSON number literal.
+func isValidNumber(s string) bool {
+       // This function implements the JSON numbers grammar.
+       // See https://tools.ietf.org/html/rfc7159#section-6
+       // and http://json.org/number.gif
+
+       if s == "" {
+               return false
+       }
+
+       // Optional -
+       if s[0] == '-' {
+               s = s[1:]
+               if s == "" {
+                       return false
+               }
+       }
+
+       // Digits
+       switch {
+       default:
+               return false
+
+       case s[0] == '0':
+               s = s[1:]
+
+       case '1' <= s[0] && s[0] <= '9':
+               s = s[1:]
+               for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
+                       s = s[1:]
+               }
+       }
+
+       // . followed by 1 or more digits.
+       if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' {
+               s = s[2:]
+               for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
+                       s = s[1:]
+               }
+       }
+
+       // e or E followed by an optional - or + and
+       // 1 or more digits.
+       if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') {
+               s = s[1:]
+               if s[0] == '+' || s[0] == '-' {
+                       s = s[1:]
+                       if s == "" {
+                               return false
+                       }
+               }
+               for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
+                       s = s[1:]
+               }
+       }
+
+       // Make sure we are at the end.
+       return s == ""
+}
+
 // decodeState represents the state while decoding a JSON value.
 type decodeState struct {
        data       []byte
@@ -241,7 +312,7 @@ func (d *decodeState) scanWhile(op int) int {
                        newOp = d.scan.eof()
                        d.off = len(d.data) + 1 // mark processed EOF with len+1
                } else {
-                       c := int(d.data[d.off])
+                       c := d.data[d.off]
                        d.off++
                        newOp = d.scan.step(&d.scan, c)
                }
@@ -757,7 +828,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                                d.saveError(err)
                                break
                        }
-                       v.Set(reflect.ValueOf(b[0:n]))
+                       v.SetBytes(b[:n])
                case reflect.String:
                        v.SetString(string(s))
                case reflect.Interface:
@@ -781,6 +852,9 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                default:
                        if v.Kind() == reflect.String && v.Type() == numberType {
                                v.SetString(s)
+                               if !isValidNumber(s) {
+                                       d.error(fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item))
+                               }
                                break
                        }
                        if fromQuoted {
index 51b15ef997cb4f593185971652ffa74723519b5a..9546ae459cd1581edd7a87e112edb7e937fe3a46 100644 (file)
@@ -728,7 +728,7 @@ func TestErrorMessageFromMisusedString(t *testing.T) {
 }
 
 func noSpace(c rune) rune {
-       if isSpace(c) {
+       if isSpace(byte(c)) { //only used for ascii
                return -1
        }
        return c
@@ -1218,12 +1218,12 @@ func TestStringKind(t *testing.T) {
 
        data, err := Marshal(m1)
        if err != nil {
-               t.Errorf("Unexpected error marshalling: %v", err)
+               t.Errorf("Unexpected error marshaling: %v", err)
        }
 
        err = Unmarshal(data, &m2)
        if err != nil {
-               t.Errorf("Unexpected error unmarshalling: %v", err)
+               t.Errorf("Unexpected error unmarshaling: %v", err)
        }
 
        if !reflect.DeepEqual(m1, m2) {
@@ -1253,6 +1253,27 @@ func TestByteKind(t *testing.T) {
        }
 }
 
+// The fix for issue 8962 introduced a regression.
+// Issue 12921.
+func TestSliceOfCustomByte(t *testing.T) {
+       type Uint8 uint8
+
+       a := []Uint8("hello")
+
+       data, err := Marshal(a)
+       if err != nil {
+               t.Fatal(err)
+       }
+       var b []Uint8
+       err = Unmarshal(data, &b)
+       if err != nil {
+               t.Fatal(err)
+       }
+       if !reflect.DeepEqual(a, b) {
+               t.Fatal("expected %v == %v", a, b)
+       }
+}
+
 var decodeTypeErrorTests = []struct {
        dest interface{}
        src  string
index e829a930768ba1e00793fdda131fed156834cdfc..69ac7e03c8db81c2ebcc5d14765e6b5a3a441215 100644 (file)
@@ -14,6 +14,7 @@ import (
        "bytes"
        "encoding"
        "encoding/base64"
+       "fmt"
        "math"
        "reflect"
        "runtime"
@@ -30,7 +31,10 @@ import (
 // Marshal traverses the value v recursively.
 // If an encountered value implements the Marshaler interface
 // and is not a nil pointer, Marshal calls its MarshalJSON method
-// to produce JSON.  The nil pointer exception is not strictly necessary
+// to produce JSON. If no MarshalJSON method is present but the
+// value implements encoding.TextMarshaler instead, Marshal calls
+// its MarshalText method.
+// The nil pointer exception is not strictly necessary
 // but mimics a similar, necessary exception in the behavior of
 // UnmarshalJSON.
 //
@@ -445,12 +449,10 @@ func textMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
        }
        m := v.Interface().(encoding.TextMarshaler)
        b, err := m.MarshalText()
-       if err == nil {
-               _, err = e.stringBytes(b)
-       }
        if err != nil {
                e.error(&MarshalerError{v.Type(), err})
        }
+       e.stringBytes(b)
 }
 
 func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
@@ -461,12 +463,10 @@ func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
        }
        m := va.Interface().(encoding.TextMarshaler)
        b, err := m.MarshalText()
-       if err == nil {
-               _, err = e.stringBytes(b)
-       }
        if err != nil {
                e.error(&MarshalerError{v.Type(), err})
        }
+       e.stringBytes(b)
 }
 
 func boolEncoder(e *encodeState, v reflect.Value, quoted bool) {
@@ -530,9 +530,14 @@ var (
 func stringEncoder(e *encodeState, v reflect.Value, quoted bool) {
        if v.Type() == numberType {
                numStr := v.String()
+               // In Go1.5 the empty string encodes to "0", while this is not a valid number literal
+               // we keep compatibility so check validity after this.
                if numStr == "" {
                        numStr = "0" // Number's zero-val
                }
+               if !isValidNumber(numStr) {
+                       e.error(fmt.Errorf("json: invalid number literal %q", numStr))
+               }
                e.WriteString(numStr)
                return
        }
@@ -780,7 +785,7 @@ func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
 func (sv stringValues) get(i int) string   { return sv[i].String() }
 
 // NOTE: keep in sync with stringBytes below.
-func (e *encodeState) string(s string) (int, error) {
+func (e *encodeState) string(s string) int {
        len0 := e.Len()
        e.WriteByte('"')
        start := 0
@@ -852,11 +857,11 @@ func (e *encodeState) string(s string) (int, error) {
                e.WriteString(s[start:])
        }
        e.WriteByte('"')
-       return e.Len() - len0, nil
+       return e.Len() - len0
 }
 
 // NOTE: keep in sync with string above.
-func (e *encodeState) stringBytes(s []byte) (int, error) {
+func (e *encodeState) stringBytes(s []byte) int {
        len0 := e.Len()
        e.WriteByte('"')
        start := 0
@@ -928,7 +933,7 @@ func (e *encodeState) stringBytes(s []byte) (int, error) {
                e.Write(s[start:])
        }
        e.WriteByte('"')
-       return e.Len() - len0, nil
+       return e.Len() - len0
 }
 
 // A field represents a single field found in a struct.
index 7abfa85db7bc243c6c057a476297dce62cc9c5f7..c00491e00c03163f1c1512819308fea548aef0de 100644 (file)
@@ -381,16 +381,10 @@ func TestStringBytes(t *testing.T) {
                r = append(r, i)
        }
        s := string(r) + "\xff\xff\xffhello" // some invalid UTF-8 too
-       _, err := es.string(s)
-       if err != nil {
-               t.Fatal(err)
-       }
+       es.string(s)
 
        esBytes := &encodeState{}
-       _, err = esBytes.stringBytes([]byte(s))
-       if err != nil {
-               t.Fatal(err)
-       }
+       esBytes.stringBytes([]byte(s))
 
        enc := es.Buffer.String()
        encBytes := esBytes.Buffer.String()
@@ -443,6 +437,18 @@ func TestIssue6458(t *testing.T) {
        }
 }
 
+func TestIssue10281(t *testing.T) {
+       type Foo struct {
+               N Number
+       }
+       x := Foo{Number(`invalid`)}
+
+       b, err := Marshal(&x)
+       if err == nil {
+               t.Errorf("Marshal(&x) = %#q; want error", b)
+       }
+}
+
 func TestHTMLEscape(t *testing.T) {
        var b, want bytes.Buffer
        m := `{"M":"<html>foo &` + "\xe2\x80\xa8 \xe2\x80\xa9" + `</html>"}`
index e1bacafd6b860e2e2d5bbf081b4bbd41b09ebcf4..7cd9f4db184a7df373603b18f8f98be1c941f89e 100644 (file)
@@ -36,7 +36,7 @@ func compact(dst *bytes.Buffer, src []byte, escape bool) error {
                        dst.WriteByte(hex[src[i+2]&0xF])
                        start = i + 3
                }
-               v := scan.step(&scan, int(c))
+               v := scan.step(&scan, c)
                if v >= scanSkipSpace {
                        if v == scanError {
                                break
@@ -70,8 +70,12 @@ func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
 // indented line beginning with prefix followed by one or more
 // copies of indent according to the indentation nesting.
 // 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.
+// any indentation, to make it easier to embed inside other formatted JSON data.
+// Although leading space characters (space, tab, carriage return, newline)
+// at the beginning of src are dropped, trailing space characters
+// at the end of src are preserved and copied to dst.
+// For example, if src has no trailing spaces, neither will dst;
+// if src ends in a trailing newline, so will dst.
 func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
        origLen := dst.Len()
        var scan scanner
@@ -80,7 +84,7 @@ func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
        depth := 0
        for _, c := range src {
                scan.bytes++
-               v := scan.step(&scan, int(c))
+               v := scan.step(&scan, c)
                if v == scanSkipSpace {
                        continue
                }
diff --git a/libgo/go/encoding/json/number_test.go b/libgo/go/encoding/json/number_test.go
new file mode 100644 (file)
index 0000000..4e63cf9
--- /dev/null
@@ -0,0 +1,133 @@
+// 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 json
+
+import (
+       "regexp"
+       "testing"
+)
+
+func TestNumberIsValid(t *testing.T) {
+       // From: http://stackoverflow.com/a/13340826
+       var jsonNumberRegexp = regexp.MustCompile(`^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$`)
+
+       validTests := []string{
+               "0",
+               "-0",
+               "1",
+               "-1",
+               "0.1",
+               "-0.1",
+               "1234",
+               "-1234",
+               "12.34",
+               "-12.34",
+               "12E0",
+               "12E1",
+               "12e34",
+               "12E-0",
+               "12e+1",
+               "12e-34",
+               "-12E0",
+               "-12E1",
+               "-12e34",
+               "-12E-0",
+               "-12e+1",
+               "-12e-34",
+               "1.2E0",
+               "1.2E1",
+               "1.2e34",
+               "1.2E-0",
+               "1.2e+1",
+               "1.2e-34",
+               "-1.2E0",
+               "-1.2E1",
+               "-1.2e34",
+               "-1.2E-0",
+               "-1.2e+1",
+               "-1.2e-34",
+               "0E0",
+               "0E1",
+               "0e34",
+               "0E-0",
+               "0e+1",
+               "0e-34",
+               "-0E0",
+               "-0E1",
+               "-0e34",
+               "-0E-0",
+               "-0e+1",
+               "-0e-34",
+       }
+
+       for _, test := range validTests {
+               if !isValidNumber(test) {
+                       t.Errorf("%s should be valid", test)
+               }
+
+               var f float64
+               if err := Unmarshal([]byte(test), &f); err != nil {
+                       t.Errorf("%s should be valid but Unmarshal failed: %v", test, err)
+               }
+
+               if !jsonNumberRegexp.MatchString(test) {
+                       t.Errorf("%s should be valid but regexp does not match", test)
+               }
+       }
+
+       invalidTests := []string{
+               "",
+               "invalid",
+               "1.0.1",
+               "1..1",
+               "-1-2",
+               "012a42",
+               "01.2",
+               "012",
+               "12E12.12",
+               "1e2e3",
+               "1e+-2",
+               "1e--23",
+               "1e",
+               "e1",
+               "1e+",
+               "1ea",
+               "1a",
+               "1.a",
+               "1.",
+               "01",
+               "1.e1",
+       }
+
+       for _, test := range invalidTests {
+               if isValidNumber(test) {
+                       t.Errorf("%s should be invalid", test)
+               }
+
+               var f float64
+               if err := Unmarshal([]byte(test), &f); err == nil {
+                       t.Errorf("%s should be invalid but unmarshal wrote %v", test, f)
+               }
+
+               if jsonNumberRegexp.MatchString(test) {
+                       t.Errorf("%s should be invalid but matches regexp", test)
+               }
+       }
+}
+
+func BenchmarkNumberIsValid(b *testing.B) {
+       s := "-61657.61667E+61673"
+       for i := 0; i < b.N; i++ {
+               isValidNumber(s)
+       }
+}
+
+func BenchmarkNumberIsValidRegexp(b *testing.B) {
+       var jsonNumberRegexp = regexp.MustCompile(`^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$`)
+       s := "-61657.61667E+61673"
+       for i := 0; i < b.N; i++ {
+               jsonNumberRegexp.MatchString(s)
+       }
+}
index 38d0b0802b356b09c2b0ecfe782d592afd3be960..ee6622e8cf844b64932ab7ac7caf2c88cff4b28c 100644 (file)
@@ -21,7 +21,7 @@ func checkValid(data []byte, scan *scanner) error {
        scan.reset()
        for _, c := range data {
                scan.bytes++
-               if scan.step(scan, int(c)) == scanError {
+               if scan.step(scan, c) == scanError {
                        return scan.err
                }
        }
@@ -37,7 +37,7 @@ func checkValid(data []byte, scan *scanner) error {
 func nextValue(data []byte, scan *scanner) (value, rest []byte, err error) {
        scan.reset()
        for i, c := range data {
-               v := scan.step(scan, int(c))
+               v := scan.step(scan, c)
                if v >= scanEndObject {
                        switch v {
                        // probe the scanner with a space to determine whether we will
@@ -50,7 +50,7 @@ func nextValue(data []byte, scan *scanner) (value, rest []byte, err error) {
                        case scanError:
                                return nil, nil, scan.err
                        case scanEnd:
-                               return data[0:i], data[i:], nil
+                               return data[:i], data[i:], nil
                        }
                }
        }
@@ -85,7 +85,7 @@ type scanner struct {
        // Also tried using an integer constant and a single func
        // with a switch, but using the func directly was 10% faster
        // on a 64-bit Mac Mini, and it's nicer to read.
-       step func(*scanner, int) int
+       step func(*scanner, byte) int
 
        // Reached end of top-level value.
        endTop bool
@@ -99,7 +99,7 @@ type scanner struct {
        // 1-byte redo (see undo method)
        redo      bool
        redoCode  int
-       redoState func(*scanner, int) int
+       redoState func(*scanner, byte) int
 
        // total bytes consumed, updated by decoder.Decode
        bytes int64
@@ -188,13 +188,13 @@ func (s *scanner) popParseState() {
        }
 }
 
-func isSpace(c rune) bool {
+func isSpace(c byte) bool {
        return c == ' ' || c == '\t' || c == '\r' || c == '\n'
 }
 
 // stateBeginValueOrEmpty is the state after reading `[`.
-func stateBeginValueOrEmpty(s *scanner, c int) int {
-       if c <= ' ' && isSpace(rune(c)) {
+func stateBeginValueOrEmpty(s *scanner, c byte) int {
+       if c <= ' ' && isSpace(c) {
                return scanSkipSpace
        }
        if c == ']' {
@@ -204,8 +204,8 @@ func stateBeginValueOrEmpty(s *scanner, c int) int {
 }
 
 // stateBeginValue is the state at the beginning of the input.
-func stateBeginValue(s *scanner, c int) int {
-       if c <= ' ' && isSpace(rune(c)) {
+func stateBeginValue(s *scanner, c byte) int {
+       if c <= ' ' && isSpace(c) {
                return scanSkipSpace
        }
        switch c {
@@ -244,8 +244,8 @@ func stateBeginValue(s *scanner, c int) int {
 }
 
 // stateBeginStringOrEmpty is the state after reading `{`.
-func stateBeginStringOrEmpty(s *scanner, c int) int {
-       if c <= ' ' && isSpace(rune(c)) {
+func stateBeginStringOrEmpty(s *scanner, c byte) int {
+       if c <= ' ' && isSpace(c) {
                return scanSkipSpace
        }
        if c == '}' {
@@ -257,8 +257,8 @@ func stateBeginStringOrEmpty(s *scanner, c int) int {
 }
 
 // stateBeginString is the state after reading `{"key": value,`.
-func stateBeginString(s *scanner, c int) int {
-       if c <= ' ' && isSpace(rune(c)) {
+func stateBeginString(s *scanner, c byte) int {
+       if c <= ' ' && isSpace(c) {
                return scanSkipSpace
        }
        if c == '"' {
@@ -270,7 +270,7 @@ func stateBeginString(s *scanner, c int) int {
 
 // stateEndValue is the state after completing a value,
 // such as after reading `{}` or `true` or `["x"`.
-func stateEndValue(s *scanner, c int) int {
+func stateEndValue(s *scanner, c byte) int {
        n := len(s.parseState)
        if n == 0 {
                // Completed top-level before the current byte.
@@ -278,7 +278,7 @@ func stateEndValue(s *scanner, c int) int {
                s.endTop = true
                return stateEndTop(s, c)
        }
-       if c <= ' ' && isSpace(rune(c)) {
+       if c <= ' ' && isSpace(c) {
                s.step = stateEndValue
                return scanSkipSpace
        }
@@ -319,7 +319,7 @@ func stateEndValue(s *scanner, c int) int {
 // stateEndTop is the state after finishing the top-level value,
 // such as after reading `{}` or `[1,2,3]`.
 // Only space characters should be seen now.
-func stateEndTop(s *scanner, c int) int {
+func stateEndTop(s *scanner, c byte) int {
        if c != ' ' && c != '\t' && c != '\r' && c != '\n' {
                // Complain about non-space byte on next call.
                s.error(c, "after top-level value")
@@ -328,7 +328,7 @@ func stateEndTop(s *scanner, c int) int {
 }
 
 // stateInString is the state after reading `"`.
-func stateInString(s *scanner, c int) int {
+func stateInString(s *scanner, c byte) int {
        if c == '"' {
                s.step = stateEndValue
                return scanContinue
@@ -344,13 +344,12 @@ func stateInString(s *scanner, c int) int {
 }
 
 // stateInStringEsc is the state after reading `"\` during a quoted string.
-func stateInStringEsc(s *scanner, c int) int {
+func stateInStringEsc(s *scanner, c byte) int {
        switch c {
        case 'b', 'f', 'n', 'r', 't', '\\', '/', '"':
                s.step = stateInString
                return scanContinue
-       }
-       if c == 'u' {
+       case 'u':
                s.step = stateInStringEscU
                return scanContinue
        }
@@ -358,7 +357,7 @@ func stateInStringEsc(s *scanner, c int) int {
 }
 
 // stateInStringEscU is the state after reading `"\u` during a quoted string.
-func stateInStringEscU(s *scanner, c int) int {
+func stateInStringEscU(s *scanner, c byte) int {
        if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
                s.step = stateInStringEscU1
                return scanContinue
@@ -368,7 +367,7 @@ func stateInStringEscU(s *scanner, c int) int {
 }
 
 // stateInStringEscU1 is the state after reading `"\u1` during a quoted string.
-func stateInStringEscU1(s *scanner, c int) int {
+func stateInStringEscU1(s *scanner, c byte) int {
        if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
                s.step = stateInStringEscU12
                return scanContinue
@@ -378,7 +377,7 @@ func stateInStringEscU1(s *scanner, c int) int {
 }
 
 // stateInStringEscU12 is the state after reading `"\u12` during a quoted string.
-func stateInStringEscU12(s *scanner, c int) int {
+func stateInStringEscU12(s *scanner, c byte) int {
        if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
                s.step = stateInStringEscU123
                return scanContinue
@@ -388,7 +387,7 @@ func stateInStringEscU12(s *scanner, c int) int {
 }
 
 // stateInStringEscU123 is the state after reading `"\u123` during a quoted string.
-func stateInStringEscU123(s *scanner, c int) int {
+func stateInStringEscU123(s *scanner, c byte) int {
        if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
                s.step = stateInString
                return scanContinue
@@ -398,7 +397,7 @@ func stateInStringEscU123(s *scanner, c int) int {
 }
 
 // stateNeg is the state after reading `-` during a number.
-func stateNeg(s *scanner, c int) int {
+func stateNeg(s *scanner, c byte) int {
        if c == '0' {
                s.step = state0
                return scanContinue
@@ -412,7 +411,7 @@ func stateNeg(s *scanner, c int) int {
 
 // state1 is the state after reading a non-zero integer during a number,
 // such as after reading `1` or `100` but not `0`.
-func state1(s *scanner, c int) int {
+func state1(s *scanner, c byte) int {
        if '0' <= c && c <= '9' {
                s.step = state1
                return scanContinue
@@ -421,7 +420,7 @@ func state1(s *scanner, c int) int {
 }
 
 // state0 is the state after reading `0` during a number.
-func state0(s *scanner, c int) int {
+func state0(s *scanner, c byte) int {
        if c == '.' {
                s.step = stateDot
                return scanContinue
@@ -435,7 +434,7 @@ func state0(s *scanner, c int) int {
 
 // stateDot is the state after reading the integer and decimal point in a number,
 // such as after reading `1.`.
-func stateDot(s *scanner, c int) int {
+func stateDot(s *scanner, c byte) int {
        if '0' <= c && c <= '9' {
                s.step = stateDot0
                return scanContinue
@@ -445,9 +444,8 @@ func stateDot(s *scanner, c int) int {
 
 // stateDot0 is the state after reading the integer, decimal point, and subsequent
 // digits of a number, such as after reading `3.14`.
-func stateDot0(s *scanner, c int) int {
+func stateDot0(s *scanner, c byte) int {
        if '0' <= c && c <= '9' {
-               s.step = stateDot0
                return scanContinue
        }
        if c == 'e' || c == 'E' {
@@ -459,12 +457,8 @@ func stateDot0(s *scanner, c int) int {
 
 // stateE is the state after reading the mantissa and e in a number,
 // such as after reading `314e` or `0.314e`.
-func stateE(s *scanner, c int) int {
-       if c == '+' {
-               s.step = stateESign
-               return scanContinue
-       }
-       if c == '-' {
+func stateE(s *scanner, c byte) int {
+       if c == '+' || c == '-' {
                s.step = stateESign
                return scanContinue
        }
@@ -473,7 +467,7 @@ func stateE(s *scanner, c int) int {
 
 // stateESign is the state after reading the mantissa, e, and sign in a number,
 // such as after reading `314e-` or `0.314e+`.
-func stateESign(s *scanner, c int) int {
+func stateESign(s *scanner, c byte) int {
        if '0' <= c && c <= '9' {
                s.step = stateE0
                return scanContinue
@@ -484,16 +478,15 @@ func stateESign(s *scanner, c int) int {
 // stateE0 is the state after reading the mantissa, e, optional sign,
 // and at least one digit of the exponent in a number,
 // such as after reading `314e-2` or `0.314e+1` or `3.14e0`.
-func stateE0(s *scanner, c int) int {
+func stateE0(s *scanner, c byte) int {
        if '0' <= c && c <= '9' {
-               s.step = stateE0
                return scanContinue
        }
        return stateEndValue(s, c)
 }
 
 // stateT is the state after reading `t`.
-func stateT(s *scanner, c int) int {
+func stateT(s *scanner, c byte) int {
        if c == 'r' {
                s.step = stateTr
                return scanContinue
@@ -502,7 +495,7 @@ func stateT(s *scanner, c int) int {
 }
 
 // stateTr is the state after reading `tr`.
-func stateTr(s *scanner, c int) int {
+func stateTr(s *scanner, c byte) int {
        if c == 'u' {
                s.step = stateTru
                return scanContinue
@@ -511,7 +504,7 @@ func stateTr(s *scanner, c int) int {
 }
 
 // stateTru is the state after reading `tru`.
-func stateTru(s *scanner, c int) int {
+func stateTru(s *scanner, c byte) int {
        if c == 'e' {
                s.step = stateEndValue
                return scanContinue
@@ -520,7 +513,7 @@ func stateTru(s *scanner, c int) int {
 }
 
 // stateF is the state after reading `f`.
-func stateF(s *scanner, c int) int {
+func stateF(s *scanner, c byte) int {
        if c == 'a' {
                s.step = stateFa
                return scanContinue
@@ -529,7 +522,7 @@ func stateF(s *scanner, c int) int {
 }
 
 // stateFa is the state after reading `fa`.
-func stateFa(s *scanner, c int) int {
+func stateFa(s *scanner, c byte) int {
        if c == 'l' {
                s.step = stateFal
                return scanContinue
@@ -538,7 +531,7 @@ func stateFa(s *scanner, c int) int {
 }
 
 // stateFal is the state after reading `fal`.
-func stateFal(s *scanner, c int) int {
+func stateFal(s *scanner, c byte) int {
        if c == 's' {
                s.step = stateFals
                return scanContinue
@@ -547,7 +540,7 @@ func stateFal(s *scanner, c int) int {
 }
 
 // stateFals is the state after reading `fals`.
-func stateFals(s *scanner, c int) int {
+func stateFals(s *scanner, c byte) int {
        if c == 'e' {
                s.step = stateEndValue
                return scanContinue
@@ -556,7 +549,7 @@ func stateFals(s *scanner, c int) int {
 }
 
 // stateN is the state after reading `n`.
-func stateN(s *scanner, c int) int {
+func stateN(s *scanner, c byte) int {
        if c == 'u' {
                s.step = stateNu
                return scanContinue
@@ -565,7 +558,7 @@ func stateN(s *scanner, c int) int {
 }
 
 // stateNu is the state after reading `nu`.
-func stateNu(s *scanner, c int) int {
+func stateNu(s *scanner, c byte) int {
        if c == 'l' {
                s.step = stateNul
                return scanContinue
@@ -574,7 +567,7 @@ func stateNu(s *scanner, c int) int {
 }
 
 // stateNul is the state after reading `nul`.
-func stateNul(s *scanner, c int) int {
+func stateNul(s *scanner, c byte) int {
        if c == 'l' {
                s.step = stateEndValue
                return scanContinue
@@ -584,19 +577,19 @@ func stateNul(s *scanner, c int) int {
 
 // stateError is the state after reaching a syntax error,
 // such as after reading `[1}` or `5.1.2`.
-func stateError(s *scanner, c int) int {
+func stateError(s *scanner, c byte) int {
        return scanError
 }
 
 // error records an error and switches to the error state.
-func (s *scanner) error(c int, context string) int {
+func (s *scanner) error(c byte, context string) int {
        s.step = stateError
        s.err = &SyntaxError{"invalid character " + quoteChar(c) + " " + context, s.bytes}
        return scanError
 }
 
 // quoteChar formats c as a quoted character literal
-func quoteChar(c int) string {
+func quoteChar(c byte) string {
        // special cases - different from quoted strings
        if c == '\'' {
                return `'\''`
@@ -623,7 +616,7 @@ func (s *scanner) undo(scanCode int) {
 }
 
 // stateRedo helps implement the scanner's 1-byte undo.
-func stateRedo(s *scanner, c int) int {
+func stateRedo(s *scanner, c byte) int {
        s.redo = false
        s.step = s.redoState
        return s.redoCode
index dc53bceff85ebe6e6a4fe73f799db1cf2978a4fc..8ddcf4d279ec16073ddfd2b22dffed5983071074 100644 (file)
@@ -90,7 +90,7 @@ Input:
                // Look in the buffer for a new value.
                for i, c := range dec.buf[scanp:] {
                        dec.scan.bytes++
-                       v := dec.scan.step(&dec.scan, int(c))
+                       v := dec.scan.step(&dec.scan, c)
                        if v == scanEnd {
                                scanp += i
                                break Input
@@ -157,7 +157,7 @@ func (dec *Decoder) refill() error {
 
 func nonSpace(b []byte) bool {
        for _, c := range b {
-               if !isSpace(rune(c)) {
+               if !isSpace(c) {
                        return true
                }
        }
@@ -433,7 +433,7 @@ func (dec *Decoder) tokenError(c byte) (Token, error) {
        case tokenObjectComma:
                context = " after object key:value pair"
        }
-       return nil, &SyntaxError{"invalid character " + quoteChar(int(c)) + " " + context, 0}
+       return nil, &SyntaxError{"invalid character " + quoteChar(c) + " " + context, 0}
 }
 
 // More reports whether there is another element in the
@@ -448,7 +448,7 @@ func (dec *Decoder) peek() (byte, error) {
        for {
                for i := dec.scanp; i < len(dec.buf); i++ {
                        c := dec.buf[i]
-                       if isSpace(rune(c)) {
+                       if isSpace(c) {
                                continue
                        }
                        dec.scanp = i
index ab656c6261c4012a112b7a9e426d5e6589c41ae4..958dbc1a3a6d1026e3bb0a6b976ee14b5b03d691 100644 (file)
@@ -155,20 +155,28 @@ func TestFuzz(t *testing.T) {
                }
 
                var buf bytes.Buffer
-               err := Encode(&buf, &block)
-               decoded, rest := Decode(buf.Bytes())
-
-               switch {
-               case err != nil:
+               if err := Encode(&buf, &block); err != nil {
                        t.Errorf("Encode of %#v resulted in error: %s", &block, err)
-               case !reflect.DeepEqual(&block, decoded):
+                       return false
+               }
+               decoded, rest := Decode(buf.Bytes())
+               if block.Headers == nil {
+                       // Encoder supports nil Headers but decoder returns initialized.
+                       block.Headers = make(map[string]string)
+               }
+               if block.Bytes == nil {
+                       // Encoder supports nil Bytes but decoder returns initialized.
+                       block.Bytes = make([]byte, 0)
+               }
+               if !reflect.DeepEqual(decoded, &block) {
                        t.Errorf("Encode of %#v decoded as %#v", &block, decoded)
-               case len(rest) != 0:
+                       return false
+               }
+               if len(rest) != 0 {
                        t.Errorf("Encode of %#v decoded correctly, but with %x left over", block, rest)
-               default:
-                       return true
+                       return false
                }
-               return false
+               return true
        }
 
        // Explicitly test the empty block.
index 86d1422a5bd53fbc458c358079e5e0940b9161c5..8ebd693030eb78b939458fe0c6e608ad523878e9 100644 (file)
@@ -48,6 +48,8 @@ const (
 //       field name in the XML element.
 //     - a field with tag ",chardata" is written as character data,
 //       not as an XML element.
+//     - a field with tag ",cdata" is written as character data
+//       wrapped in one or more <![CDATA[ ... ]]> tags, not as an XML element.
 //     - a field with tag ",innerxml" is written verbatim, not subject
 //       to the usual marshalling procedure.
 //     - a field with tag ",comment" is written as an XML comment, not
@@ -768,7 +770,11 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
                }
 
                switch finfo.flags & fMode {
-               case fCharData:
+               case fCDATA, fCharData:
+                       emit := EscapeText
+                       if finfo.flags&fMode == fCDATA {
+                               emit = emitCDATA
+                       }
                        if err := s.trim(finfo.parents); err != nil {
                                return err
                        }
@@ -777,7 +783,9 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
                                if err != nil {
                                        return err
                                }
-                               Escape(p, data)
+                               if err := emit(p, data); err != nil {
+                                       return err
+                               }
                                continue
                        }
                        if vf.CanAddr() {
@@ -787,27 +795,37 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
                                        if err != nil {
                                                return err
                                        }
-                                       Escape(p, data)
+                                       if err := emit(p, data); err != nil {
+                                               return err
+                                       }
                                        continue
                                }
                        }
                        var scratch [64]byte
                        switch vf.Kind() {
                        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-                               Escape(p, strconv.AppendInt(scratch[:0], vf.Int(), 10))
+                               if err := emit(p, strconv.AppendInt(scratch[:0], vf.Int(), 10)); err != nil {
+                                       return err
+                               }
                        case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-                               Escape(p, strconv.AppendUint(scratch[:0], vf.Uint(), 10))
+                               if err := emit(p, strconv.AppendUint(scratch[:0], vf.Uint(), 10)); err != nil {
+                                       return err
+                               }
                        case reflect.Float32, reflect.Float64:
-                               Escape(p, strconv.AppendFloat(scratch[:0], vf.Float(), 'g', -1, vf.Type().Bits()))
+                               if err := emit(p, strconv.AppendFloat(scratch[:0], vf.Float(), 'g', -1, vf.Type().Bits())); err != nil {
+                                       return err
+                               }
                        case reflect.Bool:
-                               Escape(p, strconv.AppendBool(scratch[:0], vf.Bool()))
+                               if err := emit(p, strconv.AppendBool(scratch[:0], vf.Bool())); err != nil {
+                                       return err
+                               }
                        case reflect.String:
-                               if err := EscapeText(p, []byte(vf.String())); err != nil {
+                               if err := emit(p, []byte(vf.String())); err != nil {
                                        return err
                                }
                        case reflect.Slice:
                                if elem, ok := vf.Interface().([]byte); ok {
-                                       if err := EscapeText(p, elem); err != nil {
+                                       if err := emit(p, elem); err != nil {
                                                return err
                                        }
                                }
index ef6c20e949b3139f4973c323c52cdf393610cdc7..fe8b16fe43145b63bfba444c554c66028df96381 100644 (file)
@@ -356,6 +356,15 @@ type NestedAndComment struct {
        Comment string   `xml:",comment"`
 }
 
+type CDataTest struct {
+       Chardata string `xml:",cdata"`
+}
+
+type NestedAndCData struct {
+       AB    []string `xml:"A>B"`
+       CDATA string   `xml:",cdata"`
+}
+
 func ifaceptr(x interface{}) interface{} {
        return &x
 }
@@ -978,6 +987,42 @@ var marshalTests = []struct {
                        MyInt: 42,
                },
        },
+       // Test outputting CDATA-wrapped text.
+       {
+               ExpectXML: `<CDataTest></CDataTest>`,
+               Value:     &CDataTest{},
+       },
+       {
+               ExpectXML: `<CDataTest><![CDATA[http://example.com/tests/1?foo=1&bar=baz]]></CDataTest>`,
+               Value: &CDataTest{
+                       Chardata: "http://example.com/tests/1?foo=1&bar=baz",
+               },
+       },
+       {
+               ExpectXML: `<CDataTest><![CDATA[Literal <![CDATA[Nested]]]]><![CDATA[>!]]></CDataTest>`,
+               Value: &CDataTest{
+                       Chardata: "Literal <![CDATA[Nested]]>!",
+               },
+       },
+       {
+               ExpectXML: `<CDataTest><![CDATA[<![CDATA[Nested]]]]><![CDATA[> Literal!]]></CDataTest>`,
+               Value: &CDataTest{
+                       Chardata: "<![CDATA[Nested]]> Literal!",
+               },
+       },
+       {
+               ExpectXML: `<CDataTest><![CDATA[<![CDATA[Nested]]]]><![CDATA[> Literal! <![CDATA[Nested]]]]><![CDATA[> Literal!]]></CDataTest>`,
+               Value: &CDataTest{
+                       Chardata: "<![CDATA[Nested]]> Literal! <![CDATA[Nested]]> Literal!",
+               },
+       },
+       {
+               ExpectXML: `<CDataTest><![CDATA[<![CDATA[<![CDATA[Nested]]]]><![CDATA[>]]]]><![CDATA[>]]></CDataTest>`,
+               Value: &CDataTest{
+                       Chardata: "<![CDATA[<![CDATA[Nested]]>]]>",
+               },
+       },
+
        // Test omitempty with parent chain; see golang.org/issue/4168.
        {
                ExpectXML: `<Strings><A></A></Strings>`,
@@ -1016,6 +1061,10 @@ var marshalTests = []struct {
                ExpectXML: `<NestedAndComment><A><B></B><B></B></A><!--test--></NestedAndComment>`,
                Value:     &NestedAndComment{AB: make([]string, 2), Comment: "test"},
        },
+       {
+               ExpectXML: `<NestedAndCData><A><B></B><B></B></A><![CDATA[test]]></NestedAndCData>`,
+               Value:     &NestedAndCData{AB: make([]string, 2), CDATA: "test"},
+       },
 }
 
 func TestMarshal(t *testing.T) {
@@ -1705,7 +1754,7 @@ func TestRace9796(t *testing.T) {
        for i := 0; i < 2; i++ {
                wg.Add(1)
                go func() {
-                       Marshal(B{[]A{A{}}})
+                       Marshal(B{[]A{{}}})
                        wg.Done()
                }()
        }
index 75b9f2ba1b2ee44fad5e1a72e53058c988364db2..77b4c7b4955b720cd8538aeea29ca71ac1a904e4 100644 (file)
@@ -431,7 +431,7 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
                                        }
                                }
 
-                       case fCharData:
+                       case fCDATA, fCharData:
                                if !saveData.IsValid() {
                                        saveData = finfo.value(sv)
                                }
index 7d004dc488cdfe7a6bd9bb29e0278acae9b4b514..7a98092803add05e7d5b1aa50a7dba0891050757 100644 (file)
@@ -712,3 +712,24 @@ func TestUnmarshalIntoInterface(t *testing.T) {
                t.Errorf("failed to unmarshal into interface, have %q want %q", have, want)
        }
 }
+
+type X struct {
+       D string `xml:",comment"`
+}
+
+// Issue 11112. Unmarshal must reject invalid comments.
+func TestMalformedComment(t *testing.T) {
+       testData := []string{
+               "<X><!-- a---></X>",
+               "<X><!-- -- --></X>",
+               "<X><!-- a--b --></X>",
+               "<X><!------></X>",
+       }
+       for i, test := range testData {
+               data := []byte(test)
+               v := new(X)
+               if err := Unmarshal(data, v); err == nil {
+                       t.Errorf("%d: unmarshal should reject invalid comments", i)
+               }
+       }
+}
index 6766b88f09a194546589ca2f320dcc063d62ea0f..6483c8dbe67e0bd22f64ee92b55e194b1f48aa94 100644 (file)
@@ -31,6 +31,7 @@ type fieldFlags int
 const (
        fElement fieldFlags = 1 << iota
        fAttr
+       fCDATA
        fCharData
        fInnerXml
        fComment
@@ -38,7 +39,7 @@ const (
 
        fOmitEmpty
 
-       fMode = fElement | fAttr | fCharData | fInnerXml | fComment | fAny
+       fMode = fElement | fAttr | fCDATA | fCharData | fInnerXml | fComment | fAny
 )
 
 var tinfoMap = make(map[reflect.Type]*typeInfo)
@@ -130,6 +131,8 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro
                        switch flag {
                        case "attr":
                                finfo.flags |= fAttr
+                       case "cdata":
+                               finfo.flags |= fCDATA
                        case "chardata":
                                finfo.flags |= fCharData
                        case "innerxml":
@@ -148,7 +151,7 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro
                switch mode := finfo.flags & fMode; mode {
                case 0:
                        finfo.flags |= fElement
-               case fAttr, fCharData, fInnerXml, fComment, fAny:
+               case fAttr, fCDATA, fCharData, fInnerXml, fComment, fAny:
                        if f.Name == "XMLName" || tag != "" && mode != fAttr {
                                valid = false
                        }
index 0a21c9305310341812f95d48bdd55fdc4f117fdd..45f4157318a49ac59751655751160d848a91f0a9 100644 (file)
@@ -227,7 +227,8 @@ func NewDecoder(r io.Reader) *Decoder {
 //
 // Token guarantees that the StartElement and EndElement
 // tokens it returns are properly nested and matched:
-// if Token encounters an unexpected end element,
+// if Token encounters an unexpected end element
+// or EOF before all expected end elements,
 // it will return an error.
 //
 // Token implements XML name spaces as described by
@@ -245,6 +246,9 @@ func (d *Decoder) Token() (t Token, err error) {
                t = d.nextToken
                d.nextToken = nil
        } else if t, err = d.rawToken(); err != nil {
+               if err == io.EOF && d.stk != nil && d.stk.kind != stkEOF {
+                       err = d.syntaxError("unexpected EOF")
+               }
                return
        }
 
@@ -580,7 +584,7 @@ func (d *Decoder) rawToken() (Token, error) {
                                return nil, d.err
                        }
                        enc := procInst("encoding", content)
-                       if enc != "" && enc != "utf-8" && enc != "UTF-8" {
+                       if enc != "" && enc != "utf-8" && enc != "UTF-8" && !strings.EqualFold(enc, "utf-8") {
                                if d.CharsetReader == nil {
                                        d.err = fmt.Errorf("xml: encoding %q declared but Decoder.CharsetReader is nil", enc)
                                        return nil, d.err
@@ -621,7 +625,12 @@ func (d *Decoder) rawToken() (Token, error) {
                                        return nil, d.err
                                }
                                d.buf.WriteByte(b)
-                               if b0 == '-' && b1 == '-' && b == '>' {
+                               if b0 == '-' && b1 == '-' {
+                                       if b != '>' {
+                                               d.err = d.syntaxError(
+                                                       `invalid sequence "--" not allowed in comments`)
+                                               return nil, d.err
+                                       }
                                        break
                                }
                                b0, b1 = b1, b
@@ -1940,6 +1949,46 @@ func Escape(w io.Writer, s []byte) {
        EscapeText(w, s)
 }
 
+var (
+       cdataStart  = []byte("<![CDATA[")
+       cdataEnd    = []byte("]]>")
+       cdataEscape = []byte("]]]]><![CDATA[>")
+)
+
+// emitCDATA writes to w the CDATA-wrapped plain text data s.
+// It escapes CDATA directives nested in s.
+func emitCDATA(w io.Writer, s []byte) error {
+       if len(s) == 0 {
+               return nil
+       }
+       if _, err := w.Write(cdataStart); err != nil {
+               return err
+       }
+       for {
+               i := bytes.Index(s, cdataEnd)
+               if i >= 0 && i+len(cdataEnd) <= len(s) {
+                       // Found a nested CDATA directive end.
+                       if _, err := w.Write(s[:i]); err != nil {
+                               return err
+                       }
+                       if _, err := w.Write(cdataEscape); err != nil {
+                               return err
+                       }
+                       i += len(cdataEnd)
+               } else {
+                       if _, err := w.Write(s); err != nil {
+                               return err
+                       }
+                       break
+               }
+               s = s[i:]
+       }
+       if _, err := w.Write(cdataEnd); err != nil {
+               return err
+       }
+       return nil
+}
+
 // procInst parses the `param="..."` or `param='...'`
 // value out of the provided string, returning "" if not found.
 func procInst(param, s string) string {
index 312a7c98a5c50488fda5a98bed217598b6300eb0..5d5e4bf9709cfa59112b5519f6df9567f6dcc31a 100644 (file)
@@ -750,3 +750,56 @@ func TestIssue5880(t *testing.T) {
                t.Errorf("Marshal generated invalid UTF-8: %x", data)
        }
 }
+
+func TestIssue11405(t *testing.T) {
+       testCases := []string{
+               "<root>",
+               "<root><foo>",
+               "<root><foo></foo>",
+       }
+       for _, tc := range testCases {
+               d := NewDecoder(strings.NewReader(tc))
+               var err error
+               for {
+                       _, err = d.Token()
+                       if err != nil {
+                               break
+                       }
+               }
+               if _, ok := err.(*SyntaxError); !ok {
+                       t.Errorf("%s: Token: Got error %v, want SyntaxError", tc, err)
+               }
+       }
+}
+
+func TestIssue12417(t *testing.T) {
+       testCases := []struct {
+               s  string
+               ok bool
+       }{
+               {`<?xml encoding="UtF-8" version="1.0"?><root/>`, true},
+               {`<?xml encoding="UTF-8" version="1.0"?><root/>`, true},
+               {`<?xml encoding="utf-8" version="1.0"?><root/>`, true},
+               {`<?xml encoding="uuu-9" version="1.0"?><root/>`, false},
+       }
+       for _, tc := range testCases {
+               d := NewDecoder(strings.NewReader(tc.s))
+               var err error
+               for {
+                       _, err = d.Token()
+                       if err != nil {
+                               if err == io.EOF {
+                                       err = nil
+                               }
+                               break
+                       }
+               }
+               if err != nil && tc.ok {
+                       t.Errorf("%q: Encoding charset: expected no error, got %s", tc.s, err)
+                       continue
+               }
+               if err == nil && !tc.ok {
+                       t.Errorf("%q: Encoding charset: expected error, got nil", tc.s)
+               }
+       }
+}
index ef91368ef0849dcc20f03f58cfa0ab7dfc605ec5..4eea48eb6b0095ce2eecc7684e7ba6a316ef8657 100644 (file)
@@ -34,8 +34,8 @@
                %b      decimalless scientific notation with exponent a power of two,
                        in the manner of strconv.FormatFloat with the 'b' format,
                        e.g. -123456p-78
-               %e      scientific notation, e.g. -1234.456e+78
-               %E      scientific notation, e.g. -1234.456E+78
+               %e      scientific notation, e.g. -1.234456e+78
+               %E      scientific notation, e.g. -1.234456E+78
                %f      decimal point but no exponent, e.g. 123.456
                %F      synonym for %f
                %g      %e for large exponents, %f otherwise
        formatting considerations apply for operands that implement
        certain interfaces. In order of application:
 
-       1. If the operand is a reflect.Value, the concrete value it
-       holds is printed as if it was the operand.
+       1. If the operand is a reflect.Value, the operand is replaced by the
+       concrete value that it holds, and printing continues with the next rule.
 
        2. If an operand implements the Formatter interface, it will
        be invoked. Formatter provides fine control of formatting.
index 8f3587b55054fce319875056b003c205b9ee6a60..ea6392feb6b6e0c264633ceeedaa9ff145a35e6e 100644 (file)
@@ -7,6 +7,7 @@ package fmt_test
 import (
        "bytes"
        . "fmt"
+       "internal/race"
        "io"
        "math"
        "reflect"
@@ -984,7 +985,7 @@ func TestCountMallocs(t *testing.T) {
                t.Skip("skipping malloc count in short mode")
        case runtime.GOMAXPROCS(0) > 1:
                t.Skip("skipping; GOMAXPROCS>1")
-       case raceenabled:
+       case race.Enabled:
                t.Skip("skipping malloc count under race detector")
        }
        for _, mt := range mallocTest {
@@ -1190,6 +1191,11 @@ var startests = []struct {
        {"%.*d", args(4, 42), "0042"},
        {"%*.*d", args(8, 4, 42), "    0042"},
        {"%0*d", args(4, 42), "0042"},
+       // Some non-int types for width. (Issue 10732).
+       {"%0*d", args(uint(4), 42), "0042"},
+       {"%0*d", args(uint64(4), 42), "0042"},
+       {"%0*d", args('\x04', 42), "0042"},
+       {"%0*d", args(uintptr(4), 42), "0042"},
 
        // erroneous
        {"%*d", args(nil, 42), "%!(BADWIDTH)42"},
@@ -1198,17 +1204,19 @@ var startests = []struct {
        {"%.*d", args(nil, 42), "%!(BADPREC)42"},
        {"%.*d", args(-1, 42), "%!(BADPREC)42"},
        {"%.*d", args(int(1e7), 42), "%!(BADPREC)42"},
+       {"%.*d", args(uint(1e7), 42), "%!(BADPREC)42"},
+       {"%.*d", args(uint64(1<<63), 42), "%!(BADPREC)42"},   // Huge negative (-inf).
+       {"%.*d", args(uint64(1<<64-1), 42), "%!(BADPREC)42"}, // Small negative (-1).
        {"%*d", args(5, "foo"), "%!d(string=  foo)"},
        {"%*% %d", args(20, 5), "% 5"},
        {"%*", args(4), "%!(NOVERB)"},
-       {"%*d", args(int32(4), 42), "%!(BADWIDTH)42"},
 }
 
 func TestWidthAndPrecision(t *testing.T) {
-       for _, tt := range startests {
+       for i, tt := range startests {
                s := Sprintf(tt.fmt, tt.in...)
                if s != tt.out {
-                       t.Errorf("%q: got %q expected %q", tt.fmt, s, tt.out)
+                       t.Errorf("#%d: %q: got %q expected %q", i, tt.fmt, s, tt.out)
                }
        }
 }
index 8d3e97c3ab1b7da8959a71218302a73ceef89f57..ebfa13e4d370a16515f064c3d7930fbf3379463b 100644 (file)
@@ -1024,11 +1024,30 @@ BigSwitch:
        return wasString
 }
 
-// intFromArg gets the argNumth element of a. On return, isInt reports whether the argument has type int.
+// intFromArg gets the argNumth element of a. On return, isInt reports whether the argument has integer type.
 func intFromArg(a []interface{}, argNum int) (num int, isInt bool, newArgNum int) {
        newArgNum = argNum
        if argNum < len(a) {
-               num, isInt = a[argNum].(int)
+               num, isInt = a[argNum].(int) // Almost always OK.
+               if !isInt {
+                       // Work harder.
+                       switch v := reflect.ValueOf(a[argNum]); v.Kind() {
+                       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+                               n := v.Int()
+                               if int64(int(n)) == n {
+                                       num = int(n)
+                                       isInt = true
+                               }
+                       case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+                               n := v.Uint()
+                               if int64(n) >= 0 && uint64(int(n)) == n {
+                                       num = int(n)
+                                       isInt = true
+                               }
+                       default:
+                               // Already 0, false.
+                       }
+               }
                newArgNum = argNum + 1
                if tooLarge(num) {
                        num = 0
index e3e0fd0b5858d79d84a8888159aa567da7c594ee..4618ed4a827f4ee41e10f7f53fb3796bf161b984 100644 (file)
@@ -538,7 +538,7 @@ func (s *ss) okVerb(verb rune, okVerbs, typ string) bool {
                        return true
                }
        }
-       s.errorString("bad verb %" + string(verb) + " for " + typ)
+       s.errorString("bad verb '%" + string(verb) + "' for " + typ)
        return false
 }
 
@@ -813,7 +813,7 @@ func (s *ss) scanComplex(verb rune, n int) complex128 {
 // convertString returns the string represented by the next input characters.
 // The format of the input is determined by the verb.
 func (s *ss) convertString(verb rune) (str string) {
-       if !s.okVerb(verb, "svqx", "string") {
+       if !s.okVerb(verb, "svqxX", "string") {
                return ""
        }
        s.skipSpace(false)
@@ -821,7 +821,7 @@ func (s *ss) convertString(verb rune) (str string) {
        switch verb {
        case 'q':
                str = s.quotedString()
-       case 'x':
+       case 'x', 'X':
                str = s.hexString()
        default:
                str = string(s.token(true, notSpace)) // %s and %v just return the next word
@@ -1078,6 +1078,10 @@ func (s *ss) advance(format string) (i int) {
        for i < len(format) {
                fmtc, w := utf8.DecodeRuneInString(format[i:])
                if fmtc == '%' {
+                       // % at end of string is an error.
+                       if i+w == len(format) {
+                               s.errorString("missing verb: % at end of format string")
+                       }
                        // %% acts like a real percent
                        nextc, _ := utf8.DecodeRuneInString(format[i+w:]) // will not match % if string is empty
                        if nextc != '%' {
@@ -1179,7 +1183,7 @@ func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err erro
                }
 
                if numProcessed >= len(a) { // out of operands
-                       s.errorString("too few operands for format %" + format[i-w:])
+                       s.errorString("too few operands for format '%" + format[i-w:] + "'")
                        break
                }
                arg := a[numProcessed]
index 334c4a6b2428b944f9c71b9904067862f0a72b89..7ac74dcb4bd7ce1b22ce050e6ea8609b8b9fbb93 100644 (file)
@@ -255,12 +255,14 @@ var scanfTests = []ScanfTest{
        // Strings
        {"%s", "using-%s\n", &stringVal, "using-%s"},
        {"%x", "7573696e672d2578\n", &stringVal, "using-%x"},
+       {"%X", "7573696E672D2558\n", &stringVal, "using-%X"},
        {"%q", `"quoted\twith\\do\u0075bl\x65s"` + "\n", &stringVal, "quoted\twith\\doubles"},
        {"%q", "`quoted with backs`\n", &stringVal, "quoted with backs"},
 
        // Byte slices
        {"%s", "bytes-%s\n", &bytesVal, []byte("bytes-%s")},
        {"%x", "62797465732d2578\n", &bytesVal, []byte("bytes-%x")},
+       {"%X", "62797465732D2558\n", &bytesVal, []byte("bytes-%X")},
        {"%q", `"bytes\rwith\vdo\u0075bl\x65s"` + "\n", &bytesVal, []byte("bytes\rwith\vdoubles")},
        {"%q", "`bytes with backs`\n", &bytesVal, []byte("bytes with backs")},
 
@@ -291,6 +293,7 @@ var scanfTests = []ScanfTest{
        // Interesting formats
        {"here is\tthe value:%d", "here is   the\tvalue:118\n", &intVal, 118},
        {"%% %%:%d", "% %:119\n", &intVal, 119},
+       {"%d%%", "42%", &intVal, 42}, // %% at end of string.
 
        // Corner cases
        {"%x", "FFFFFFFF\n", &uint32Val, uint32(0xFFFFFFFF)},
@@ -356,6 +359,8 @@ var multiTests = []ScanfMultiTest{
        {"%d %d", "23 18 27", args(&i, &j, &k), args(23, 18), "too many operands"},
        {"%c", "\u0100", args(&int8Val), nil, "overflow"},
        {"X%d", "10X", args(&intVal), nil, "input does not match format"},
+       {"%d%", "42%", args(&intVal), args(42), "missing verb: % at end of format string"},
+       {"%d% ", "42%", args(&intVal), args(42), "too few operands for format '% '"}, // Slightly odd error, but correct.
 
        // Bad UTF-8: should see every byte.
        {"%c%c%c", "\xc2X\xc2", args(&r1, &r2, &r3), args(utf8.RuneError, 'X', utf8.RuneError), ""},
index d2770d16cf862b8346832ee985a3bfb2624e051b..5c794c3e79821648e67b7dbabd0f97908c795a14 100644 (file)
@@ -43,8 +43,10 @@ func SortImports(fset *token.FileSet, f *File) {
                if len(d.Specs) > 0 {
                        lastSpec := d.Specs[len(d.Specs)-1]
                        lastLine := fset.Position(lastSpec.Pos()).Line
-                       if rParenLine := fset.Position(d.Rparen).Line; rParenLine > lastLine+1 {
-                               fset.File(d.Rparen).MergeLine(rParenLine - 1)
+                       rParenLine := fset.Position(d.Rparen).Line
+                       for rParenLine > lastLine+1 {
+                               rParenLine--
+                               fset.File(d.Rparen).MergeLine(rParenLine)
                        }
                }
        }
index 42f11655b39f2c7e0131ef7eec2c7f8e3a73324d..2f570c334dc5f46c09b3001a818085b786dceff2 100644 (file)
@@ -110,7 +110,7 @@ func (ctxt *Context) splitPathList(s string) []string {
        return filepath.SplitList(s)
 }
 
-// isAbsPath calls ctxt.IsAbsSPath (if not nil) or else filepath.IsAbs.
+// isAbsPath calls ctxt.IsAbsPath (if not nil) or else filepath.IsAbs.
 func (ctxt *Context) isAbsPath(path string) bool {
        if f := ctxt.IsAbsPath; f != nil {
                return f(path)
@@ -294,7 +294,7 @@ func defaultContext() Context {
 
        c.GOARCH = envOr("GOARCH", runtime.GOARCH)
        c.GOOS = envOr("GOOS", runtime.GOOS)
-       c.GOROOT = runtime.GOROOT()
+       c.GOROOT = pathpkg.Clean(runtime.GOROOT())
        c.GOPATH = envOr("GOPATH", "")
        c.Compiler = runtime.Compiler
 
@@ -303,7 +303,7 @@ func defaultContext() Context {
        // in all releases >= Go 1.x. Code that requires Go 1.x or later should
        // 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".
-       c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5"}
+       c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6"}
 
        switch os.Getenv("CGO_ENABLED") {
        case "1":
@@ -348,6 +348,21 @@ const (
        // or finds conflicting comments in multiple source files.
        // See golang.org/s/go14customimport for more information.
        ImportComment
+
+       // By default, Import searches vendor directories
+       // that apply in the given source directory before searching
+       // the GOROOT and GOPATH roots.
+       // If an Import finds and returns a package using a vendor
+       // directory, the resulting ImportPath is the complete path
+       // to the package, including the path elements leading up
+       // to and including "vendor".
+       // For example, if Import("y", "x/subdir", 0) finds
+       // "x/vendor/y", the returned package's ImportPath is "x/vendor/y",
+       // not plain "y".
+       // See golang.org/s/go15vendor for more information.
+       //
+       // Setting IgnoreVendor ignores vendor directories.
+       IgnoreVendor
 )
 
 // A Package describes the Go package found in a directory.
@@ -371,6 +386,7 @@ type Package struct {
        GoFiles        []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
        CgoFiles       []string // .go source files that import "C"
        IgnoredGoFiles []string // .go source files ignored for this build
+       InvalidGoFiles []string // .go source files with detected problems (parse error, wrong package name, and so on)
        CFiles         []string // .c source files
        CXXFiles       []string // .cc, .cpp and .cxx source files
        MFiles         []string // .m (Objective-C) source files
@@ -479,15 +495,22 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
        switch ctxt.Compiler {
        case "gccgo":
                pkgtargetroot = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
-               dir, elem := pathpkg.Split(p.ImportPath)
-               pkga = pkgtargetroot + "/" + dir + "lib" + elem + ".a"
        case "gc":
                pkgtargetroot = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
-               pkga = pkgtargetroot + "/" + p.ImportPath + ".a"
        default:
                // Save error for end of function.
                pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler)
        }
+       setPkga := func() {
+               switch ctxt.Compiler {
+               case "gccgo":
+                       dir, elem := pathpkg.Split(p.ImportPath)
+                       pkga = pkgtargetroot + "/" + dir + "lib" + elem + ".a"
+               case "gc":
+                       pkga = pkgtargetroot + "/" + p.ImportPath + ".a"
+               }
+       }
+       setPkga()
 
        binaryOnly := false
        if IsLocalImport(path) {
@@ -548,9 +571,50 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
 
                // tried records the location of unsuccessful package lookups
                var tried struct {
+                       vendor []string
                        goroot string
                        gopath []string
                }
+               gopath := ctxt.gopath()
+
+               // Vendor directories get first chance to satisfy import.
+               if mode&IgnoreVendor == 0 && srcDir != "" {
+                       searchVendor := func(root string, isGoroot bool) bool {
+                               sub, ok := ctxt.hasSubdir(root, srcDir)
+                               if !ok || !strings.HasPrefix(sub, "src/") || strings.Contains(sub, "/testdata/") {
+                                       return false
+                               }
+                               for {
+                                       vendor := ctxt.joinPath(root, sub, "vendor")
+                                       if ctxt.isDir(vendor) {
+                                               dir := ctxt.joinPath(vendor, path)
+                                               if ctxt.isDir(dir) && hasGoFiles(ctxt, dir) {
+                                                       p.Dir = dir
+                                                       p.ImportPath = strings.TrimPrefix(pathpkg.Join(sub, "vendor", path), "src/")
+                                                       p.Goroot = isGoroot
+                                                       p.Root = root
+                                                       setPkga() // p.ImportPath changed
+                                                       return true
+                                               }
+                                               tried.vendor = append(tried.vendor, dir)
+                                       }
+                                       i := strings.LastIndex(sub, "/")
+                                       if i < 0 {
+                                               break
+                                       }
+                                       sub = sub[:i]
+                               }
+                               return false
+                       }
+                       if searchVendor(ctxt.GOROOT, true) {
+                               goto Found
+                       }
+                       for _, root := range gopath {
+                               if searchVendor(root, false) {
+                                       goto Found
+                               }
+                       }
+               }
 
                // Determine directory from import path.
                if ctxt.GOROOT != "" {
@@ -565,7 +629,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
                        }
                        tried.goroot = dir
                }
-               for _, root := range ctxt.gopath() {
+               for _, root := range gopath {
                        dir := ctxt.joinPath(root, "src", path)
                        isDir := ctxt.isDir(dir)
                        binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(root, pkga))
@@ -579,20 +643,22 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
 
                // package was not found
                var paths []string
+               format := "\t%s (vendor tree)"
+               for _, dir := range tried.vendor {
+                       paths = append(paths, fmt.Sprintf(format, dir))
+                       format = "\t%s"
+               }
                if tried.goroot != "" {
                        paths = append(paths, fmt.Sprintf("\t%s (from $GOROOT)", tried.goroot))
                } else {
                        paths = append(paths, "\t($GOROOT not set)")
                }
-               var i int
-               var format = "\t%s (from $GOPATH)"
-               for ; i < len(tried.gopath); i++ {
-                       if i > 0 {
-                               format = "\t%s"
-                       }
-                       paths = append(paths, fmt.Sprintf(format, tried.gopath[i]))
+               format = "\t%s (from $GOPATH)"
+               for _, dir := range tried.gopath {
+                       paths = append(paths, fmt.Sprintf(format, dir))
+                       format = "\t%s"
                }
-               if i == 0 {
+               if len(tried.gopath) == 0 {
                        paths = append(paths, "\t($GOPATH not set)")
                }
                return p, fmt.Errorf("cannot find package %q in any of:\n%s", path, strings.Join(paths, "\n"))
@@ -621,6 +687,7 @@ Found:
                return p, err
        }
 
+       var badGoError error
        var Sfiles []string // files with ".S" (capital S)
        var firstFile, firstCommentFile string
        imported := make(map[string][]token.Position)
@@ -636,9 +703,17 @@ Found:
                name := d.Name()
                ext := nameExt(name)
 
+               badFile := func(err error) {
+                       if badGoError == nil {
+                               badGoError = err
+                       }
+                       p.InvalidGoFiles = append(p.InvalidGoFiles, name)
+               }
+
                match, data, filename, err := ctxt.matchFile(p.Dir, name, true, allTags)
                if err != nil {
-                       return p, err
+                       badFile(err)
+                       continue
                }
                if !match {
                        if ext == ".go" {
@@ -683,7 +758,8 @@ Found:
 
                pf, err := parser.ParseFile(fset, filename, data, parser.ImportsOnly|parser.ParseComments)
                if err != nil {
-                       return p, err
+                       badFile(err)
+                       continue
                }
 
                pkg := pf.Name.Name
@@ -703,11 +779,12 @@ Found:
                        p.Name = pkg
                        firstFile = name
                } else if pkg != p.Name {
-                       return p, &MultiplePackageError{
+                       badFile(&MultiplePackageError{
                                Dir:      p.Dir,
                                Packages: []string{p.Name, pkg},
                                Files:    []string{firstFile, name},
-                       }
+                       })
+                       p.InvalidGoFiles = append(p.InvalidGoFiles, name)
                }
                if pf.Doc != nil && p.Doc == "" {
                        p.Doc = doc.Synopsis(pf.Doc.Text())
@@ -718,13 +795,12 @@ Found:
                        if line != 0 {
                                com, err := strconv.Unquote(qcom)
                                if err != nil {
-                                       return p, fmt.Errorf("%s:%d: cannot parse import comment", filename, line)
-                               }
-                               if p.ImportComment == "" {
+                                       badFile(fmt.Errorf("%s:%d: cannot parse import comment", filename, line))
+                               } else if p.ImportComment == "" {
                                        p.ImportComment = com
                                        firstCommentFile = name
                                } else if p.ImportComment != com {
-                                       return p, fmt.Errorf("found import comments %q (%s) and %q (%s) in %s", p.ImportComment, firstCommentFile, com, name, p.Dir)
+                                       badFile(fmt.Errorf("found import comments %q (%s) and %q (%s) in %s", p.ImportComment, firstCommentFile, com, name, p.Dir))
                                }
                        }
                }
@@ -755,18 +831,19 @@ Found:
                                }
                                if path == "C" {
                                        if isTest {
-                                               return p, fmt.Errorf("use of cgo in test %s not supported", filename)
-                                       }
-                                       cg := spec.Doc
-                                       if cg == nil && len(d.Specs) == 1 {
-                                               cg = d.Doc
-                                       }
-                                       if cg != nil {
-                                               if err := ctxt.saveCgo(filename, p, cg); err != nil {
-                                                       return p, err
+                                               badFile(fmt.Errorf("use of cgo in test %s not supported", filename))
+                                       } else {
+                                               cg := spec.Doc
+                                               if cg == nil && len(d.Specs) == 1 {
+                                                       cg = d.Doc
+                                               }
+                                               if cg != nil {
+                                                       if err := ctxt.saveCgo(filename, p, cg); err != nil {
+                                                               badFile(err)
+                                                       }
                                                }
+                                               isCgo = true
                                        }
-                                       isCgo = true
                                }
                        }
                }
@@ -785,6 +862,9 @@ Found:
                        p.GoFiles = append(p.GoFiles, name)
                }
        }
+       if badGoError != nil {
+               return p, badGoError
+       }
        if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
                return p, &NoGoError{p.Dir}
        }
@@ -809,6 +889,20 @@ Found:
        return p, pkgerr
 }
 
+// hasGoFiles reports whether dir contains any files with names ending in .go.
+// For a vendor check we must exclude directories that contain no .go files.
+// Otherwise it is not possible to vendor just a/b/c and still import the
+// non-vendored a/b. See golang.org/issue/13832.
+func hasGoFiles(ctxt *Context, dir string) bool {
+       ents, _ := ctxt.readDir(dir)
+       for _, ent := range ents {
+               if !ent.IsDir() && strings.HasSuffix(ent.Name(), ".go") {
+                       return true
+               }
+       }
+       return false
+}
+
 func findImportComment(data []byte) (s string, line int) {
        // expect keyword package
        word, data := parseWord(data)
@@ -1132,9 +1226,9 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup)
                if err != nil {
                        return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
                }
+               var ok bool
                for i, arg := range args {
-                       arg = expandSrcDir(arg, di.Dir)
-                       if !safeCgoName(arg) {
+                       if arg, ok = expandSrcDir(arg, di.Dir); !ok {
                                return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg)
                        }
                        args[i] = arg
@@ -1158,25 +1252,47 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup)
        return nil
 }
 
-func expandSrcDir(str string, srcdir string) string {
+// expandSrcDir expands any occurrence of ${SRCDIR}, making sure
+// the result is safe for the shell.
+func expandSrcDir(str string, srcdir string) (string, bool) {
        // "\" delimited paths cause safeCgoName to fail
        // so convert native paths with a different delimeter
-       // to "/" before starting (eg: on windows)
+       // to "/" before starting (eg: on windows).
        srcdir = filepath.ToSlash(srcdir)
-       return strings.Replace(str, "${SRCDIR}", srcdir, -1)
+
+       // Spaces are tolerated in ${SRCDIR}, but not anywhere else.
+       chunks := strings.Split(str, "${SRCDIR}")
+       if len(chunks) < 2 {
+               return str, safeCgoName(str, false)
+       }
+       ok := true
+       for _, chunk := range chunks {
+               ok = ok && (chunk == "" || safeCgoName(chunk, false))
+       }
+       ok = ok && (srcdir == "" || safeCgoName(srcdir, true))
+       res := strings.Join(chunks, srcdir)
+       return res, ok && res != ""
 }
 
 // NOTE: $ is not safe for the shell, but it is allowed here because of linker options like -Wl,$ORIGIN.
 // We never pass these arguments to a shell (just to programs we construct argv for), so this should be okay.
 // See golang.org/issue/6038.
-var safeBytes = []byte("+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$")
+// The @ is for OS X. See golang.org/issue/13720.
+const safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@"
+const safeSpaces = " "
 
-func safeCgoName(s string) bool {
+var safeBytes = []byte(safeSpaces + safeString)
+
+func safeCgoName(s string, spaces bool) bool {
        if s == "" {
                return false
        }
+       safe := safeBytes
+       if !spaces {
+               safe = safe[len(safeSpaces):]
+       }
        for i := 0; i < len(s); i++ {
-               if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
+               if c := s[i]; c < 0x80 && bytes.IndexByte(safe, c) < 0 {
                        return false
                }
        }
index 2709ca34f54f6c8f86909083fc979d433a8abb66..4d705b6fb2854034ac84e1b23cbfe6570209a1fb 100644 (file)
@@ -5,6 +5,7 @@
 package build
 
 import (
+       "internal/testenv"
        "io"
        "os"
        "path/filepath"
@@ -269,7 +270,7 @@ var expandSrcDirTests = []struct {
 
 func TestExpandSrcDir(t *testing.T) {
        for _, test := range expandSrcDirTests {
-               output := expandSrcDir(test.input, expandSrcDirPath)
+               output, _ := expandSrcDir(test.input, expandSrcDirPath)
                if output != test.expected {
                        t.Errorf("%q expands to %q with SRCDIR=%q when %q is expected", test.input, output, expandSrcDirPath, test.expected)
                } else {
@@ -277,3 +278,73 @@ func TestExpandSrcDir(t *testing.T) {
                }
        }
 }
+
+func TestShellSafety(t *testing.T) {
+       tests := []struct {
+               input, srcdir, expected string
+               result                  bool
+       }{
+               {"-I${SRCDIR}/../include", "/projects/src/issue 11868", "-I/projects/src/issue 11868/../include", true},
+               {"-X${SRCDIR}/1,${SRCDIR}/2", "/projects/src/issue 11868", "-X/projects/src/issue 11868/1,/projects/src/issue 11868/2", true},
+               {"-I/tmp -I/tmp", "/tmp2", "-I/tmp -I/tmp", false},
+               {"-I/tmp", "/tmp/[0]", "-I/tmp", true},
+               {"-I${SRCDIR}/dir", "/tmp/[0]", "-I/tmp/[0]/dir", false},
+       }
+       for _, test := range tests {
+               output, ok := expandSrcDir(test.input, test.srcdir)
+               if ok != test.result {
+                       t.Errorf("Expected %t while %q expands to %q with SRCDIR=%q; got %t", test.result, test.input, output, test.srcdir, ok)
+               }
+               if output != test.expected {
+                       t.Errorf("Expected %q while %q expands with SRCDIR=%q; got %q", test.expected, test.input, test.srcdir, output)
+               }
+       }
+}
+
+func TestImportVendor(t *testing.T) {
+       t.Skip("skipping; hpack has moved to internal for now; golang.org/issue/14047")
+       testenv.MustHaveGoBuild(t) // really must just have source
+       ctxt := Default
+       ctxt.GOPATH = ""
+       p, err := ctxt.Import("golang.org/x/net/http2/hpack", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
+       if err != nil {
+               t.Fatalf("cannot find vendored golang.org/x/net/http2/hpack from net/http directory: %v", err)
+       }
+       want := "vendor/golang.org/x/net/http2/hpack"
+       if p.ImportPath != want {
+               t.Fatalf("Import succeeded but found %q, want %q", p.ImportPath, want)
+       }
+}
+
+func TestImportVendorFailure(t *testing.T) {
+       testenv.MustHaveGoBuild(t) // really must just have source
+       ctxt := Default
+       ctxt.GOPATH = ""
+       p, err := ctxt.Import("x.com/y/z", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
+       if err == nil {
+               t.Fatalf("found made-up package x.com/y/z in %s", p.Dir)
+       }
+
+       e := err.Error()
+       if !strings.Contains(e, " (vendor tree)") {
+               t.Fatalf("error on failed import does not mention GOROOT/src/vendor directory:\n%s", e)
+       }
+}
+
+func TestImportVendorParentFailure(t *testing.T) {
+       testenv.MustHaveGoBuild(t) // really must just have source
+       ctxt := Default
+       ctxt.GOPATH = ""
+       // This import should fail because the vendor/golang.org/x/net/http2 directory has no source code.
+       p, err := ctxt.Import("golang.org/x/net/http2", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
+       if err == nil {
+               t.Fatalf("found empty parent in %s", p.Dir)
+       }
+       if p != nil && p.Dir != "" {
+               t.Fatalf("decided to use %s", p.Dir)
+       }
+       e := err.Error()
+       if !strings.Contains(e, " (vendor tree)") {
+               t.Fatalf("error on failed import does not mention GOROOT/src/vendor directory:\n%s", e)
+       }
+}
index 68969bbcf865f14b06df641222201f00cce6a85f..bd8b343adbe5a7ed2aa2d4331ac39958f29a7c2b 100644 (file)
@@ -34,17 +34,21 @@ import (
 //
 var pkgDeps = map[string][]string{
        // L0 is the lowest level, core, nearly unavoidable packages.
-       "errors":      {},
-       "io":          {"errors", "sync"},
-       "runtime":     {"unsafe"},
-       "sync":        {"runtime", "sync/atomic", "unsafe"},
-       "sync/atomic": {"unsafe"},
-       "unsafe":      {},
+       "errors":                  {},
+       "io":                      {"errors", "sync"},
+       "runtime":                 {"unsafe", "runtime/internal/atomic", "runtime/internal/sys"},
+       "runtime/internal/sys":    {},
+       "runtime/internal/atomic": {"unsafe", "runtime/internal/sys"},
+       "internal/race":           {"runtime", "unsafe"},
+       "sync":                    {"internal/race", "runtime", "sync/atomic", "unsafe"},
+       "sync/atomic":             {"unsafe"},
+       "unsafe":                  {},
 
        "L0": {
                "errors",
                "io",
                "runtime",
+               "runtime/internal/atomic",
                "sync",
                "sync/atomic",
                "unsafe",
@@ -128,7 +132,7 @@ var pkgDeps = map[string][]string{
        // End of linear dependency definitions.
 
        // Operating system access.
-       "syscall":                           {"L0", "unicode/utf16"},
+       "syscall":                           {"L0", "internal/race", "unicode/utf16"},
        "internal/syscall/unix":             {"L0", "syscall"},
        "internal/syscall/windows":          {"L0", "syscall"},
        "internal/syscall/windows/registry": {"L0", "syscall", "unicode/utf16"},
@@ -161,7 +165,7 @@ var pkgDeps = map[string][]string{
        "runtime/trace":  {"L0"},
        "text/tabwriter": {"L2"},
 
-       "testing":          {"L2", "flag", "fmt", "os", "runtime/pprof", "runtime/trace", "time"},
+       "testing":          {"L2", "flag", "fmt", "os", "runtime/debug", "runtime/pprof", "runtime/trace", "time"},
        "testing/iotest":   {"L2", "log"},
        "testing/quick":    {"L2", "flag", "fmt", "reflect"},
        "internal/testenv": {"L2", "os", "testing"},
@@ -214,7 +218,7 @@ var pkgDeps = map[string][]string{
        "database/sql":             {"L4", "container/list", "database/sql/driver"},
        "database/sql/driver":      {"L4", "time"},
        "debug/dwarf":              {"L4"},
-       "debug/elf":                {"L4", "OS", "debug/dwarf"},
+       "debug/elf":                {"L4", "OS", "debug/dwarf", "compress/zlib"},
        "debug/gosym":              {"L4"},
        "debug/macho":              {"L4", "OS", "debug/dwarf"},
        "debug/pe":                 {"L4", "OS", "debug/dwarf"},
@@ -256,6 +260,8 @@ var pkgDeps = map[string][]string{
        },
 
        // Cgo.
+       // If you add a dependency on CGO, you must add the package to
+       // cgoPackages in cmd/dist/test.go.
        "runtime/cgo": {"L0", "C"},
        "CGO":         {"C", "runtime/cgo"},
 
@@ -263,16 +269,17 @@ var pkgDeps = map[string][]string{
        // that shows up in programs that use cgo.
        "C": {},
 
-       // Race detector uses cgo.
+       // Race detector/MSan uses cgo.
        "runtime/race": {"C"},
+       "runtime/msan": {"C"},
 
        // Plan 9 alone needs io/ioutil and os.
        "os/user": {"L4", "CGO", "io/ioutil", "os", "syscall"},
 
        // Basic networking.
        // Because net must be used by any package that wants to
-       // do networking portably, it must have a small dependency set: just L1+basic os.
-       "net": {"L1", "CGO", "os", "syscall", "time", "internal/syscall/windows", "internal/singleflight"},
+       // do networking portably, it must have a small dependency set: just L0+basic os.
+       "net": {"L0", "CGO", "math/rand", "os", "sort", "syscall", "time", "internal/syscall/windows", "internal/singleflight", "internal/race"},
 
        // NET enables use of basic network-related packages.
        "NET": {
@@ -333,7 +340,7 @@ var pkgDeps = map[string][]string{
 
        // SSL/TLS.
        "crypto/tls": {
-               "L4", "CRYPTO-MATH", "CGO", "OS",
+               "L4", "CRYPTO-MATH", "OS",
                "container/list", "crypto/x509", "encoding/pem", "net", "syscall",
        },
        "crypto/x509": {
@@ -351,6 +358,7 @@ var pkgDeps = map[string][]string{
                "L4", "NET", "OS",
                "compress/gzip", "crypto/tls", "mime/multipart", "runtime/debug",
                "net/http/internal",
+               "internal/golang.org/x/net/http2/hpack",
        },
        "net/http/internal": {"L4"},
 
@@ -359,7 +367,7 @@ var pkgDeps = map[string][]string{
        "net/http/cgi":       {"L4", "NET", "OS", "crypto/tls", "net/http", "regexp"},
        "net/http/cookiejar": {"L4", "NET", "net/http"},
        "net/http/fcgi":      {"L4", "NET", "OS", "net/http", "net/http/cgi"},
-       "net/http/httptest":  {"L4", "NET", "OS", "crypto/tls", "flag", "net/http"},
+       "net/http/httptest":  {"L4", "NET", "OS", "crypto/tls", "flag", "net/http", "net/http/internal"},
        "net/http/httputil":  {"L4", "NET", "OS", "net/http", "net/http/internal"},
        "net/http/pprof":     {"L4", "OS", "html/template", "net/http", "runtime/pprof", "runtime/trace"},
        "net/rpc":            {"L4", "NET", "encoding/gob", "html/template", "net/http"},
@@ -454,26 +462,23 @@ func TestDependencies(t *testing.T) {
        }
        sort.Strings(all)
 
-       test := func(mustImport bool) {
-               for _, pkg := range all {
-                       imports, err := findImports(pkg)
-                       if err != nil {
-                               t.Error(err)
-                               continue
-                       }
-                       ok := allowed(pkg)
-                       var bad []string
-                       for _, imp := range imports {
-                               if !ok[imp] {
-                                       bad = append(bad, imp)
-                               }
-                       }
-                       if bad != nil {
-                               t.Errorf("unexpected dependency: %s imports %v", pkg, bad)
+       for _, pkg := range all {
+               imports, err := findImports(pkg)
+               if err != nil {
+                       t.Error(err)
+                       continue
+               }
+               ok := allowed(pkg)
+               var bad []string
+               for _, imp := range imports {
+                       if !ok[imp] {
+                               bad = append(bad, imp)
                        }
                }
+               if bad != nil {
+                       t.Errorf("unexpected dependency: %s imports %v", pkg, bad)
+               }
        }
-       test(true)
 }
 
 var buildIgnore = []byte("\n// +build ignore")
index 233f8b989d59d81f113823a884c39fd61a57e6f0..d436d28b3172b6fd8b9f8d1f9b23773948b37770 100644 (file)
 //     - "go1.3", from Go version 1.3 onward
 //     - "go1.4", from Go version 1.4 onward
 //     - "go1.5", from Go version 1.5 onward
+//     - "go1.6", from Go version 1.6 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/constant/go13.go b/libgo/go/go/constant/go13.go
deleted file mode 100644 (file)
index a4a838a..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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 !go1.4
-
-package constant
-
-import (
-       "math"
-       "math/big"
-)
-
-func ratToFloat32(x *big.Rat) (float32, bool) {
-       // Before 1.4, there's no Rat.Float32.
-       // Emulate it, albeit at the cost of
-       // imprecision in corner cases.
-       x64, exact := x.Float64()
-       x32 := float32(x64)
-       if math.IsInf(float64(x32), 0) {
-               exact = false
-       }
-       return x32, exact
-}
index 79a80af1ab1474eaaec4b3dfbe9d53b055258888..630581047a203f01d6e6c6af3a1b9f543d317a04 100644 (file)
@@ -3,8 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // Package constant implements Values representing untyped
-// Go constants and the corresponding operations. Values
-// and operations may have arbitrary or unlimited precision.
+// Go constants and their corresponding operations.
 //
 // A special Unknown value may be used when a value
 // is unknown due to an error. Operations on unknown
@@ -16,16 +15,15 @@ package constant // import "go/constant"
 import (
        "fmt"
        "go/token"
+       "math"
        "math/big"
        "strconv"
+       "unicode/utf8"
 )
 
 // Kind specifies the kind of value represented by a Value.
 type Kind int
 
-// Implementation note: Kinds must be enumerated in
-// order of increasing "complexity" (used by match).
-
 const (
        // unknown values
        Unknown Kind = iota
@@ -40,15 +38,20 @@ const (
        Complex
 )
 
-// A Value represents a mathematically exact value of a given Kind.
+// A Value represents the value of a Go constant.
 type Value interface {
-       // Kind returns the value kind; it is always the smallest
-       // kind in which the value can be represented exactly.
+       // Kind returns the value kind.
        Kind() Kind
 
-       // String returns a human-readable form of the value.
+       // String returns a short, human-readable form of the value.
+       // For numeric values, the result may be an approximation;
+       // for String values the result may be a shortened string.
+       // Use ExactString for a string representing a value exactly.
        String() string
 
+       // ExactString returns an exact, printable form of the value.
+       ExactString() string
+
        // Prevent external implementations.
        implementsValue()
 }
@@ -56,14 +59,19 @@ type Value interface {
 // ----------------------------------------------------------------------------
 // Implementations
 
+// Maximum supported mantissa precision.
+// The spec requires at least 256 bits; typical implementations use 512 bits.
+const prec = 512
+
 type (
        unknownVal struct{}
        boolVal    bool
        stringVal  string
-       int64Val   int64
-       intVal     struct{ val *big.Int }
-       floatVal   struct{ val *big.Rat }
-       complexVal struct{ re, im *big.Rat }
+       int64Val   int64                    // Int values representable as an int64
+       intVal     struct{ val *big.Int }   // Int values not representable as an int64
+       ratVal     struct{ val *big.Rat }   // Float values representable as a fraction
+       floatVal   struct{ val *big.Float } // Float values not representable as a fraction
+       complexVal struct{ re, im Value }
 )
 
 func (unknownVal) Kind() Kind { return Unknown }
@@ -71,52 +79,197 @@ func (boolVal) Kind() Kind    { return Bool }
 func (stringVal) Kind() Kind  { return String }
 func (int64Val) Kind() Kind   { return Int }
 func (intVal) Kind() Kind     { return Int }
+func (ratVal) Kind() Kind     { return Float }
 func (floatVal) Kind() Kind   { return Float }
 func (complexVal) Kind() Kind { return Complex }
 
-func (unknownVal) String() string   { return "unknown" }
-func (x boolVal) String() string    { return fmt.Sprintf("%v", bool(x)) }
-func (x stringVal) String() string  { return strconv.Quote(string(x)) }
-func (x int64Val) String() string   { return strconv.FormatInt(int64(x), 10) }
-func (x intVal) String() string     { return x.val.String() }
-func (x floatVal) String() string   { return x.val.String() }
+func (unknownVal) String() string { return "unknown" }
+func (x boolVal) String() string  { return strconv.FormatBool(bool(x)) }
+
+// String returns a possibly shortened quoted form of the String value.
+func (x stringVal) String() string {
+       const maxLen = 72 // a reasonable length
+       s := strconv.Quote(string(x))
+       if utf8.RuneCountInString(s) > maxLen {
+               // The string without the enclosing quotes is greater than maxLen-2 runes
+               // long. Remove the last 3 runes (including the closing '"') by keeping
+               // only the first maxLen-3 runes; then add "...".
+               i := 0
+               for n := 0; n < maxLen-3; n++ {
+                       _, size := utf8.DecodeRuneInString(s)
+                       i += size
+               }
+               s = s[:i] + "..."
+       }
+       return s
+}
+
+func (x int64Val) String() string { return strconv.FormatInt(int64(x), 10) }
+func (x intVal) String() string   { return x.val.String() }
+func (x ratVal) String() string   { return rtof(x).String() }
+
+// String returns returns a decimal approximation of the Float value.
+func (x floatVal) String() string {
+       f := x.val
+
+       // Don't try to convert infinities (will not terminate).
+       if f.IsInf() {
+               return f.String()
+       }
+
+       // Use exact fmt formatting if in float64 range (common case):
+       // proceed if f doesn't underflow to 0 or overflow to inf.
+       if x, _ := f.Float64(); f.Sign() == 0 == (x == 0) && !math.IsInf(x, 0) {
+               return fmt.Sprintf("%.6g", x)
+       }
+
+       // Out of float64 range. Do approximate manual to decimal
+       // conversion to avoid precise but possibly slow Float
+       // formatting.
+       // f = mant * 2**exp
+       var mant big.Float
+       exp := f.MantExp(&mant) // 0.5 <= |mant| < 1.0
+
+       // approximate float64 mantissa m and decimal exponent d
+       // f ~ m * 10**d
+       m, _ := mant.Float64()                     // 0.5 <= |m| < 1.0
+       d := float64(exp) * (math.Ln2 / math.Ln10) // log_10(2)
+
+       // adjust m for truncated (integer) decimal exponent e
+       e := int64(d)
+       m *= math.Pow(10, d-float64(e))
+
+       // ensure 1 <= |m| < 10
+       switch am := math.Abs(m); {
+       case am < 1-0.5e-6:
+               // The %.6g format below rounds m to 5 digits after the
+               // decimal point. Make sure that m*10 < 10 even after
+               // rounding up: m*10 + 0.5e-5 < 10 => m < 1 - 0.5e6.
+               m *= 10
+               e--
+       case am >= 10:
+               m /= 10
+               e++
+       }
+
+       return fmt.Sprintf("%.6ge%+d", m, e)
+}
+
 func (x complexVal) String() string { return fmt.Sprintf("(%s + %si)", x.re, x.im) }
 
+func (x unknownVal) ExactString() string { return x.String() }
+func (x boolVal) ExactString() string    { return x.String() }
+func (x stringVal) ExactString() string  { return strconv.Quote(string(x)) }
+func (x int64Val) ExactString() string   { return x.String() }
+func (x intVal) ExactString() string     { return x.String() }
+
+func (x ratVal) ExactString() string {
+       r := x.val
+       if r.IsInt() {
+               return r.Num().String()
+       }
+       return r.String()
+}
+
+func (x floatVal) ExactString() string { return x.val.Text('p', 0) }
+
+func (x complexVal) ExactString() string {
+       return fmt.Sprintf("(%s + %si)", x.re.ExactString(), x.im.ExactString())
+}
+
 func (unknownVal) implementsValue() {}
 func (boolVal) implementsValue()    {}
 func (stringVal) implementsValue()  {}
 func (int64Val) implementsValue()   {}
+func (ratVal) implementsValue()     {}
 func (intVal) implementsValue()     {}
 func (floatVal) implementsValue()   {}
 func (complexVal) implementsValue() {}
 
-// int64 bounds
+func newInt() *big.Int     { return new(big.Int) }
+func newRat() *big.Rat     { return new(big.Rat) }
+func newFloat() *big.Float { return new(big.Float).SetPrec(prec) }
+
+func i64toi(x int64Val) intVal   { return intVal{newInt().SetInt64(int64(x))} }
+func i64tor(x int64Val) ratVal   { return ratVal{newRat().SetInt64(int64(x))} }
+func i64tof(x int64Val) floatVal { return floatVal{newFloat().SetInt64(int64(x))} }
+func itor(x intVal) ratVal       { return ratVal{newRat().SetInt(x.val)} }
+func itof(x intVal) floatVal     { return floatVal{newFloat().SetInt(x.val)} }
+
+func rtof(x ratVal) floatVal {
+       a := newFloat().SetInt(x.val.Num())
+       b := newFloat().SetInt(x.val.Denom())
+       return floatVal{a.Quo(a, b)}
+}
+
+func vtoc(x Value) complexVal { return complexVal{x, int64Val(0)} }
+
 var (
        minInt64 = big.NewInt(-1 << 63)
        maxInt64 = big.NewInt(1<<63 - 1)
 )
 
-func normInt(x *big.Int) Value {
+func makeInt(x *big.Int) Value {
        if minInt64.Cmp(x) <= 0 && x.Cmp(maxInt64) <= 0 {
                return int64Val(x.Int64())
        }
        return intVal{x}
 }
 
-func normFloat(x *big.Rat) Value {
-       if x.IsInt() {
-               return normInt(x.Num())
+// Permit fractions with component sizes up to maxExp
+// before switching to using floating-point numbers.
+const maxExp = 4 << 10
+
+func makeRat(x *big.Rat) Value {
+       a := x.Num()
+       b := x.Denom()
+       if a.BitLen() < maxExp && b.BitLen() < maxExp {
+               // ok to remain fraction
+               return ratVal{x}
        }
-       return floatVal{x}
+       // components too large => switch to float
+       fa := newFloat().SetInt(a)
+       fb := newFloat().SetInt(b)
+       return floatVal{fa.Quo(fa, fb)}
 }
 
-func normComplex(re, im *big.Rat) Value {
-       if im.Sign() == 0 {
-               return normFloat(re)
+var floatVal0 = floatVal{newFloat()}
+
+func makeFloat(x *big.Float) Value {
+       // convert -0
+       if x.Sign() == 0 {
+               return floatVal0
        }
+       return floatVal{x}
+}
+
+func makeComplex(re, im Value) Value {
        return complexVal{re, im}
 }
 
+func makeFloatFromLiteral(lit string) Value {
+       if f, ok := newFloat().SetString(lit); ok {
+               if smallRat(f) {
+                       // ok to use rationals
+                       r, _ := newRat().SetString(lit)
+                       return ratVal{r}
+               }
+               // otherwise use floats
+               return makeFloat(f)
+       }
+       return nil
+}
+
+// smallRat reports whether x would lead to "reasonably"-sized fraction
+// if converted to a *big.Rat.
+func smallRat(x *big.Float) bool {
+       if !x.IsInf() {
+               e := x.MantExp(nil)
+               return -maxExp < e && e < maxExp
+       }
+       return false
+}
+
 // ----------------------------------------------------------------------------
 // Factories
 
@@ -133,62 +286,74 @@ func MakeString(s string) Value { return stringVal(s) }
 func MakeInt64(x int64) Value { return int64Val(x) }
 
 // MakeUint64 returns the Int value for x.
-func MakeUint64(x uint64) Value { return normInt(new(big.Int).SetUint64(x)) }
+func MakeUint64(x uint64) Value {
+       if x < 1<<63 {
+               return int64Val(int64(x))
+       }
+       return intVal{newInt().SetUint64(x)}
+}
 
-// MakeFloat64 returns the numeric value for x.
-// If x is not finite, the result is unknown.
+// MakeFloat64 returns the Float value for x.
+// If x is not finite, the result is an Unknown.
 func MakeFloat64(x float64) Value {
-       if f := new(big.Rat).SetFloat64(x); f != nil {
-               return normFloat(f)
+       if math.IsInf(x, 0) || math.IsNaN(x) {
+               return unknownVal{}
        }
-       return unknownVal{}
+       // convert -0 to 0
+       if x == 0 {
+               return int64Val(0)
+       }
+       return ratVal{newRat().SetFloat64(x)}
 }
 
 // MakeFromLiteral returns the corresponding integer, floating-point,
-// imaginary, character, or string value for a Go literal string.
-// If prec > 0, prec specifies an upper limit for the precision of
-// a numeric value. If the literal string is invalid, the result is
-// nil.
-// BUG(gri) Only prec == 0 is supported at the moment.
-func MakeFromLiteral(lit string, tok token.Token, prec uint) Value {
-       if prec != 0 {
-               panic("limited precision not supported")
+// imaginary, character, or string value for a Go literal string. The
+// tok value must be one of token.INT, token.FLOAT, toke.IMAG, token.
+// CHAR, or token.STRING. The final argument must be zero.
+// If the literal string syntax is invalid, the result is an Unknown.
+func MakeFromLiteral(lit string, tok token.Token, zero uint) Value {
+       if zero != 0 {
+               panic("MakeFromLiteral called with non-zero last argument")
        }
+
        switch tok {
        case token.INT:
                if x, err := strconv.ParseInt(lit, 0, 64); err == nil {
                        return int64Val(x)
                }
-               if x, ok := new(big.Int).SetString(lit, 0); ok {
+               if x, ok := newInt().SetString(lit, 0); ok {
                        return intVal{x}
                }
 
        case token.FLOAT:
-               if x, ok := new(big.Rat).SetString(lit); ok {
-                       return normFloat(x)
+               if x := makeFloatFromLiteral(lit); x != nil {
+                       return x
                }
 
        case token.IMAG:
                if n := len(lit); n > 0 && lit[n-1] == 'i' {
-                       if im, ok := new(big.Rat).SetString(lit[0 : n-1]); ok {
-                               return normComplex(big.NewRat(0, 1), im)
+                       if im := makeFloatFromLiteral(lit[:n-1]); im != nil {
+                               return makeComplex(int64Val(0), im)
                        }
                }
 
        case token.CHAR:
                if n := len(lit); n >= 2 {
                        if code, _, _, err := strconv.UnquoteChar(lit[1:n-1], '\''); err == nil {
-                               return int64Val(code)
+                               return MakeInt64(int64(code))
                        }
                }
 
        case token.STRING:
                if s, err := strconv.Unquote(lit); err == nil {
-                       return stringVal(s)
+                       return MakeString(s)
                }
+
+       default:
+               panic(fmt.Sprintf("%v is not a valid token", tok))
        }
 
-       return nil
+       return unknownVal{}
 }
 
 // ----------------------------------------------------------------------------
@@ -205,8 +370,9 @@ func BoolVal(x Value) bool {
                return bool(x)
        case unknownVal:
                return false
+       default:
+               panic(fmt.Sprintf("%v not a Bool", x))
        }
-       panic(fmt.Sprintf("%v not a Bool", x))
 }
 
 // StringVal returns the Go string value of x, which must be a String or an Unknown.
@@ -217,8 +383,9 @@ func StringVal(x Value) string {
                return string(x)
        case unknownVal:
                return ""
+       default:
+               panic(fmt.Sprintf("%v not a String", x))
        }
-       panic(fmt.Sprintf("%v not a String", x))
 }
 
 // Int64Val returns the Go int64 value of x and whether the result is exact;
@@ -229,11 +396,12 @@ func Int64Val(x Value) (int64, bool) {
        case int64Val:
                return int64(x), true
        case intVal:
-               return x.val.Int64(), x.val.BitLen() <= 63
+               return x.val.Int64(), false // not an int64Val and thus not exact
        case unknownVal:
                return 0, false
+       default:
+               panic(fmt.Sprintf("%v not an Int", x))
        }
-       panic(fmt.Sprintf("%v not an Int", x))
 }
 
 // Uint64Val returns the Go uint64 value of x and whether the result is exact;
@@ -247,8 +415,9 @@ func Uint64Val(x Value) (uint64, bool) {
                return x.val.Uint64(), x.val.Sign() >= 0 && x.val.BitLen() <= 64
        case unknownVal:
                return 0, false
+       default:
+               panic(fmt.Sprintf("%v not an Int", x))
        }
-       panic(fmt.Sprintf("%v not an Int", x))
 }
 
 // Float32Val is like Float64Val but for float32 instead of float64.
@@ -258,17 +427,22 @@ func Float32Val(x Value) (float32, bool) {
                f := float32(x)
                return f, int64Val(f) == x
        case intVal:
-               return ratToFloat32(new(big.Rat).SetFrac(x.val, int1))
+               f, acc := newFloat().SetInt(x.val).Float32()
+               return f, acc == big.Exact
+       case ratVal:
+               return x.val.Float32()
        case floatVal:
-               return ratToFloat32(x.val)
+               f, acc := x.val.Float32()
+               return f, acc == big.Exact
        case unknownVal:
                return 0, false
+       default:
+               panic(fmt.Sprintf("%v not a Float", x))
        }
-       panic(fmt.Sprintf("%v not a Float", x))
 }
 
 // Float64Val returns the nearest Go float64 value of x and whether the result is exact;
-// x must be numeric but not Complex, or Unknown. For values too small (too close to 0)
+// x must be numeric or an Unknown, but not Complex. For values too small (too close to 0)
 // to represent as float64, Float64Val silently underflows to 0. The result sign always
 // matches the sign of x, even for 0.
 // If x is Unknown, the result is (0, false).
@@ -278,13 +452,18 @@ func Float64Val(x Value) (float64, bool) {
                f := float64(int64(x))
                return f, int64Val(f) == x
        case intVal:
-               return new(big.Rat).SetFrac(x.val, int1).Float64()
-       case floatVal:
+               f, acc := newFloat().SetInt(x.val).Float64()
+               return f, acc == big.Exact
+       case ratVal:
                return x.val.Float64()
+       case floatVal:
+               f, acc := x.val.Float64()
+               return f, acc == big.Exact
        case unknownVal:
                return 0, false
+       default:
+               panic(fmt.Sprintf("%v not a Float", x))
        }
-       panic(fmt.Sprintf("%v not a Float", x))
 }
 
 // BitLen returns the number of bits required to represent
@@ -293,13 +472,14 @@ func Float64Val(x Value) (float64, bool) {
 func BitLen(x Value) int {
        switch x := x.(type) {
        case int64Val:
-               return new(big.Int).SetInt64(int64(x)).BitLen()
+               return i64toi(x).val.BitLen()
        case intVal:
                return x.val.BitLen()
        case unknownVal:
                return 0
+       default:
+               panic(fmt.Sprintf("%v not an Int", x))
        }
-       panic(fmt.Sprintf("%v not an Int", x))
 }
 
 // Sign returns -1, 0, or 1 depending on whether x < 0, x == 0, or x > 0;
@@ -317,18 +497,21 @@ func Sign(x Value) int {
                return 0
        case intVal:
                return x.val.Sign()
+       case ratVal:
+               return x.val.Sign()
        case floatVal:
                return x.val.Sign()
        case complexVal:
-               return x.re.Sign() | x.im.Sign()
+               return Sign(x.re) | Sign(x.im)
        case unknownVal:
                return 1 // avoid spurious division by zero errors
+       default:
+               panic(fmt.Sprintf("%v not numeric", x))
        }
-       panic(fmt.Sprintf("%v not numeric", x))
 }
 
 // ----------------------------------------------------------------------------
-// Support for serializing/deserializing integers
+// Support for assembling/disassembling numeric values
 
 const (
        // Compute the size of a Word in bytes.
@@ -340,17 +523,17 @@ const (
 // Bytes returns the bytes for the absolute value of x in little-
 // endian binary representation; x must be an Int.
 func Bytes(x Value) []byte {
-       var val *big.Int
+       var t intVal
        switch x := x.(type) {
        case int64Val:
-               val = new(big.Int).SetInt64(int64(x))
+               t = i64toi(x)
        case intVal:
-               val = x.val
+               t = x
        default:
                panic(fmt.Sprintf("%v not an Int", x))
        }
 
-       words := val.Bits()
+       words := t.val.Bits()
        bytes := make([]byte, len(words)*wordSize)
 
        i := 0
@@ -396,72 +579,79 @@ func MakeFromBytes(bytes []byte) Value {
                i--
        }
 
-       return normInt(new(big.Int).SetBits(words[:i]))
+       return makeInt(newInt().SetBits(words[:i]))
 }
 
-// ----------------------------------------------------------------------------
-// Support for disassembling fractions
-
 // Num returns the numerator of x; x must be Int, Float, or Unknown.
-// If x is Unknown, the result is Unknown, otherwise it is an Int
+// If x is Unknown, or if it is too large or small to represent as a
+// fraction, the result is Unknown. Otherwise the result is an Int
 // with the same sign as x.
 func Num(x Value) Value {
        switch x := x.(type) {
-       case unknownVal, int64Val, intVal:
+       case int64Val, intVal:
                return x
+       case ratVal:
+               return makeInt(x.val.Num())
        case floatVal:
-               return normInt(x.val.Num())
+               if smallRat(x.val) {
+                       r, _ := x.val.Rat(nil)
+                       return makeInt(r.Num())
+               }
+       case unknownVal:
+               break
+       default:
+               panic(fmt.Sprintf("%v not Int or Float", x))
        }
-       panic(fmt.Sprintf("%v not Int or Float", x))
+       return unknownVal{}
 }
 
 // Denom returns the denominator of x; x must be Int, Float, or Unknown.
-// If x is Unknown, the result is Unknown, otherwise it is an Int >= 1.
+// If x is Unknown, or if it is too large or small to represent as a
+// fraction, the result is Unknown. Otherwise the result is an Int >= 1.
 func Denom(x Value) Value {
        switch x := x.(type) {
-       case unknownVal:
-               return x
        case int64Val, intVal:
                return int64Val(1)
+       case ratVal:
+               return makeInt(x.val.Denom())
        case floatVal:
-               return normInt(x.val.Denom())
+               if smallRat(x.val) {
+                       r, _ := x.val.Rat(nil)
+                       return makeInt(r.Denom())
+               }
+       case unknownVal:
+               break
+       default:
+               panic(fmt.Sprintf("%v not Int or Float", x))
        }
-       panic(fmt.Sprintf("%v not Int or Float", x))
+       return unknownVal{}
 }
 
-// ----------------------------------------------------------------------------
-// Support for assembling/disassembling complex numbers
-
-// MakeImag returns the numeric value x*i (possibly 0);
+// MakeImag returns the Complex value x*i;
 // x must be Int, Float, or Unknown.
 // If x is Unknown, the result is Unknown.
 func MakeImag(x Value) Value {
-       var im *big.Rat
-       switch x := x.(type) {
+       switch x.(type) {
        case unknownVal:
                return x
-       case int64Val:
-               im = big.NewRat(int64(x), 1)
-       case intVal:
-               im = new(big.Rat).SetFrac(x.val, int1)
-       case floatVal:
-               im = x.val
+       case int64Val, intVal, ratVal, floatVal:
+               return makeComplex(int64Val(0), x)
        default:
                panic(fmt.Sprintf("%v not Int or Float", x))
        }
-       return normComplex(rat0, im)
 }
 
 // Real returns the real part of x, which must be a numeric or unknown value.
 // If x is Unknown, the result is Unknown.
 func Real(x Value) Value {
        switch x := x.(type) {
-       case unknownVal, int64Val, intVal, floatVal:
+       case unknownVal, int64Val, intVal, ratVal, floatVal:
                return x
        case complexVal:
-               return normFloat(x.re)
+               return x.re
+       default:
+               panic(fmt.Sprintf("%v not numeric", x))
        }
-       panic(fmt.Sprintf("%v not numeric", x))
 }
 
 // Imag returns the imaginary part of x, which must be a numeric or unknown value.
@@ -470,12 +660,107 @@ func Imag(x Value) Value {
        switch x := x.(type) {
        case unknownVal:
                return x
-       case int64Val, intVal, floatVal:
+       case int64Val, intVal, ratVal, floatVal:
                return int64Val(0)
        case complexVal:
-               return normFloat(x.im)
+               return x.im
+       default:
+               panic(fmt.Sprintf("%v not numeric", x))
+       }
+}
+
+// ----------------------------------------------------------------------------
+// Numeric conversions
+
+// ToInt converts x to an Int value if x is representable as an Int.
+// Otherwise it returns an Unknown.
+func ToInt(x Value) Value {
+       switch x := x.(type) {
+       case int64Val, intVal:
+               return x
+
+       case ratVal:
+               if x.val.IsInt() {
+                       return makeInt(x.val.Num())
+               }
+
+       case floatVal:
+               // avoid creation of huge integers
+               // (Existing tests require permitting exponents of at least 1024;
+               // allow any value that would also be permissible as a fraction.)
+               if smallRat(x.val) {
+                       i := newInt()
+                       if _, acc := x.val.Int(i); acc == big.Exact {
+                               return makeInt(i)
+                       }
+
+                       // If we can get an integer by rounding up or down,
+                       // assume x is not an integer because of rounding
+                       // errors in prior computations.
+
+                       const delta = 4 // a small number of bits > 0
+                       var t big.Float
+                       t.SetPrec(prec - delta)
+
+                       // try rounding down a little
+                       t.SetMode(big.ToZero)
+                       t.Set(x.val)
+                       if _, acc := t.Int(i); acc == big.Exact {
+                               return makeInt(i)
+                       }
+
+                       // try rounding up a little
+                       t.SetMode(big.AwayFromZero)
+                       t.Set(x.val)
+                       if _, acc := t.Int(i); acc == big.Exact {
+                               return makeInt(i)
+                       }
+               }
+
+       case complexVal:
+               if re := ToFloat(x); re.Kind() == Float {
+                       return ToInt(re)
+               }
+       }
+
+       return unknownVal{}
+}
+
+// ToFloat converts x to a Float value if x is representable as a Float.
+// Otherwise it returns an Unknown.
+func ToFloat(x Value) Value {
+       switch x := x.(type) {
+       case int64Val:
+               return i64tof(x)
+       case intVal:
+               return itof(x)
+       case ratVal, floatVal:
+               return x
+       case complexVal:
+               if im := ToInt(x.im); im.Kind() == Int && Sign(im) == 0 {
+                       // imaginary component is 0
+                       return ToFloat(x.re)
+               }
+       }
+       return unknownVal{}
+}
+
+// ToComplex converts x to a Complex value if x is representable as a Complex.
+// Otherwise it returns an Unknown.
+func ToComplex(x Value) Value {
+       switch x := x.(type) {
+       case int64Val:
+               return vtoc(i64tof(x))
+       case intVal:
+               return vtoc(itof(x))
+       case ratVal:
+               return vtoc(x)
+       case floatVal:
+               return vtoc(x)
+       case complexVal:
+               return x
        }
-       panic(fmt.Sprintf("%v not numeric", x))
+       return unknownVal{}
 }
 
 // ----------------------------------------------------------------------------
@@ -502,7 +787,7 @@ func UnaryOp(op token.Token, y Value, prec uint) Value {
        switch op {
        case token.ADD:
                switch y.(type) {
-               case unknownVal, int64Val, intVal, floatVal, complexVal:
+               case unknownVal, int64Val, intVal, ratVal, floatVal, complexVal:
                        return y
                }
 
@@ -514,17 +799,21 @@ func UnaryOp(op token.Token, y Value, prec uint) Value {
                        if z := -y; z != y {
                                return z // no overflow
                        }
-                       return normInt(new(big.Int).Neg(big.NewInt(int64(y))))
+                       return makeInt(newInt().Neg(big.NewInt(int64(y))))
                case intVal:
-                       return normInt(new(big.Int).Neg(y.val))
+                       return makeInt(newInt().Neg(y.val))
+               case ratVal:
+                       return makeRat(newRat().Neg(y.val))
                case floatVal:
-                       return normFloat(new(big.Rat).Neg(y.val))
+                       return makeFloat(newFloat().Neg(y.val))
                case complexVal:
-                       return normComplex(new(big.Rat).Neg(y.re), new(big.Rat).Neg(y.im))
+                       re := UnaryOp(token.SUB, y.re, 0)
+                       im := UnaryOp(token.SUB, y.im, 0)
+                       return makeComplex(re, im)
                }
 
        case token.XOR:
-               var z big.Int
+               z := newInt()
                switch y := y.(type) {
                case unknownVal:
                        return y
@@ -539,9 +828,9 @@ func UnaryOp(op token.Token, y Value, prec uint) Value {
                // thus "too large": We must limit the result precision
                // to the type's precision.
                if prec > 0 {
-                       z.AndNot(&z, new(big.Int).Lsh(big.NewInt(-1), prec)) // z &^= (-1)<<prec
+                       z.AndNot(z, newInt().Lsh(big.NewInt(-1), prec)) // z &^= (-1)<<prec
                }
-               return normInt(&z)
+               return makeInt(z)
 
        case token.NOT:
                switch y := y.(type) {
@@ -556,14 +845,9 @@ Error:
        panic(fmt.Sprintf("invalid unary operation %s%v", op, y))
 }
 
-var (
-       int1 = big.NewInt(1)
-       rat0 = big.NewRat(0, 1)
-)
-
 func ord(x Value) int {
        switch x.(type) {
-       default:
+       case unknownVal:
                return 0
        case boolVal, stringVal:
                return 1
@@ -571,10 +855,14 @@ func ord(x Value) int {
                return 2
        case intVal:
                return 3
-       case floatVal:
+       case ratVal:
                return 4
-       case complexVal:
+       case floatVal:
                return 5
+       case complexVal:
+               return 6
+       default:
+               panic("unreachable")
        }
 }
 
@@ -602,29 +890,42 @@ func match(x, y Value) (_, _ Value) {
                case int64Val:
                        return x, y
                case intVal:
-                       return intVal{big.NewInt(int64(x))}, y
+                       return i64toi(x), y
+               case ratVal:
+                       return i64tor(x), y
                case floatVal:
-                       return floatVal{big.NewRat(int64(x), 1)}, y
+                       return i64tof(x), y
                case complexVal:
-                       return complexVal{big.NewRat(int64(x), 1), rat0}, y
+                       return vtoc(x), y
                }
 
        case intVal:
                switch y := y.(type) {
                case intVal:
                        return x, y
+               case ratVal:
+                       return itor(x), y
                case floatVal:
-                       return floatVal{new(big.Rat).SetFrac(x.val, int1)}, y
+                       return itof(x), y
                case complexVal:
-                       return complexVal{new(big.Rat).SetFrac(x.val, int1), rat0}, y
+                       return vtoc(x), y
                }
 
+       case ratVal:
+               switch y := y.(type) {
+               case ratVal:
+                       return x, y
+               case floatVal:
+                       return rtof(x), y
+               case complexVal:
+                       return vtoc(x), y
+               }
        case floatVal:
                switch y := y.(type) {
                case floatVal:
                        return x, y
                case complexVal:
-                       return complexVal{x.val, rat0}, y
+                       return vtoc(x), y
                }
        }
 
@@ -661,21 +962,21 @@ func BinaryOp(x Value, op token.Token, y Value) Value {
                switch op {
                case token.ADD:
                        if !is63bit(a) || !is63bit(b) {
-                               return normInt(new(big.Int).Add(big.NewInt(a), big.NewInt(b)))
+                               return makeInt(newInt().Add(big.NewInt(a), big.NewInt(b)))
                        }
                        c = a + b
                case token.SUB:
                        if !is63bit(a) || !is63bit(b) {
-                               return normInt(new(big.Int).Sub(big.NewInt(a), big.NewInt(b)))
+                               return makeInt(newInt().Sub(big.NewInt(a), big.NewInt(b)))
                        }
                        c = a - b
                case token.MUL:
                        if !is32bit(a) || !is32bit(b) {
-                               return normInt(new(big.Int).Mul(big.NewInt(a), big.NewInt(b)))
+                               return makeInt(newInt().Mul(big.NewInt(a), big.NewInt(b)))
                        }
                        c = a * b
                case token.QUO:
-                       return normFloat(new(big.Rat).SetFrac(big.NewInt(a), big.NewInt(b)))
+                       return makeRat(big.NewRat(a, b))
                case token.QUO_ASSIGN: // force integer division
                        c = a / b
                case token.REM:
@@ -696,7 +997,7 @@ func BinaryOp(x Value, op token.Token, y Value) Value {
        case intVal:
                a := x.val
                b := y.(intVal).val
-               var c big.Int
+               c := newInt()
                switch op {
                case token.ADD:
                        c.Add(a, b)
@@ -705,7 +1006,7 @@ func BinaryOp(x Value, op token.Token, y Value) Value {
                case token.MUL:
                        c.Mul(a, b)
                case token.QUO:
-                       return normFloat(new(big.Rat).SetFrac(a, b))
+                       return makeRat(newRat().SetFrac(a, b))
                case token.QUO_ASSIGN: // force integer division
                        c.Quo(a, b)
                case token.REM:
@@ -721,12 +1022,30 @@ func BinaryOp(x Value, op token.Token, y Value) Value {
                default:
                        goto Error
                }
-               return normInt(&c)
+               return makeInt(c)
+
+       case ratVal:
+               a := x.val
+               b := y.(ratVal).val
+               c := newRat()
+               switch op {
+               case token.ADD:
+                       c.Add(a, b)
+               case token.SUB:
+                       c.Sub(a, b)
+               case token.MUL:
+                       c.Mul(a, b)
+               case token.QUO:
+                       c.Quo(a, b)
+               default:
+                       goto Error
+               }
+               return makeRat(c)
 
        case floatVal:
                a := x.val
                b := y.(floatVal).val
-               var c big.Rat
+               c := newFloat()
                switch op {
                case token.ADD:
                        c.Add(a, b)
@@ -739,49 +1058,47 @@ func BinaryOp(x Value, op token.Token, y Value) Value {
                default:
                        goto Error
                }
-               return normFloat(&c)
+               return makeFloat(c)
 
        case complexVal:
                y := y.(complexVal)
                a, b := x.re, x.im
                c, d := y.re, y.im
-               var re, im big.Rat
+               var re, im Value
                switch op {
                case token.ADD:
                        // (a+c) + i(b+d)
-                       re.Add(a, c)
-                       im.Add(b, d)
+                       re = add(a, c)
+                       im = add(b, d)
                case token.SUB:
                        // (a-c) + i(b-d)
-                       re.Sub(a, c)
-                       im.Sub(b, d)
+                       re = sub(a, c)
+                       im = sub(b, d)
                case token.MUL:
                        // (ac-bd) + i(bc+ad)
-                       var ac, bd, bc, ad big.Rat
-                       ac.Mul(a, c)
-                       bd.Mul(b, d)
-                       bc.Mul(b, c)
-                       ad.Mul(a, d)
-                       re.Sub(&ac, &bd)
-                       im.Add(&bc, &ad)
+                       ac := mul(a, c)
+                       bd := mul(b, d)
+                       bc := mul(b, c)
+                       ad := mul(a, d)
+                       re = sub(ac, bd)
+                       im = add(bc, ad)
                case token.QUO:
                        // (ac+bd)/s + i(bc-ad)/s, with s = cc + dd
-                       var ac, bd, bc, ad, s, cc, dd big.Rat
-                       ac.Mul(a, c)
-                       bd.Mul(b, d)
-                       bc.Mul(b, c)
-                       ad.Mul(a, d)
-                       cc.Mul(c, c)
-                       dd.Mul(d, d)
-                       s.Add(&cc, &dd)
-                       re.Add(&ac, &bd)
-                       re.Quo(&re, &s)
-                       im.Sub(&bc, &ad)
-                       im.Quo(&im, &s)
+                       ac := mul(a, c)
+                       bd := mul(b, d)
+                       bc := mul(b, c)
+                       ad := mul(a, d)
+                       cc := mul(c, c)
+                       dd := mul(d, d)
+                       s := add(cc, dd)
+                       re = add(ac, bd)
+                       re = quo(re, s)
+                       im = sub(bc, ad)
+                       im = quo(im, s)
                default:
                        goto Error
                }
-               return normComplex(&re, &im)
+               return makeComplex(re, im)
 
        case stringVal:
                if op == token.ADD {
@@ -793,6 +1110,11 @@ Error:
        panic(fmt.Sprintf("invalid binary operation %v %s %v", x, op, y))
 }
 
+func add(x, y Value) Value { return BinaryOp(x, token.ADD, y) }
+func sub(x, y Value) Value { return BinaryOp(x, token.SUB, y) }
+func mul(x, y Value) Value { return BinaryOp(x, token.MUL, y) }
+func quo(x, y Value) Value { return BinaryOp(x, token.QUO, y) }
+
 // Shift returns the result of the shift expression x op s
 // with op == token.SHL or token.SHR (<< or >>). x must be
 // an Int or an Unknown. If x is Unknown, the result is x.
@@ -808,8 +1130,8 @@ func Shift(x Value, op token.Token, s uint) Value {
                }
                switch op {
                case token.SHL:
-                       z := big.NewInt(int64(x))
-                       return normInt(z.Lsh(z, s))
+                       z := i64toi(x).val
+                       return makeInt(z.Lsh(z, s))
                case token.SHR:
                        return x >> s
                }
@@ -818,12 +1140,12 @@ func Shift(x Value, op token.Token, s uint) Value {
                if s == 0 {
                        return x
                }
-               var z big.Int
+               z := newInt()
                switch op {
                case token.SHL:
-                       return normInt(z.Lsh(x.val, s))
+                       return makeInt(z.Lsh(x.val, s))
                case token.SHR:
-                       return normInt(z.Rsh(x.val, s))
+                       return makeInt(z.Rsh(x.val, s))
                }
        }
 
@@ -889,18 +1211,21 @@ func Compare(x Value, op token.Token, y Value) bool {
        case intVal:
                return cmpZero(x.val.Cmp(y.(intVal).val), op)
 
+       case ratVal:
+               return cmpZero(x.val.Cmp(y.(ratVal).val), op)
+
        case floatVal:
                return cmpZero(x.val.Cmp(y.(floatVal).val), op)
 
        case complexVal:
                y := y.(complexVal)
-               re := x.re.Cmp(y.re)
-               im := x.im.Cmp(y.im)
+               re := Compare(x.re, token.EQL, y.re)
+               im := Compare(x.im, token.EQL, y.im)
                switch op {
                case token.EQL:
-                       return re == 0 && im == 0
+                       return re && im
                case token.NEQ:
-                       return re != 0 || im != 0
+                       return !re || !im
                }
 
        case stringVal:
index 08cdd5e625cb8f41928285c60e2095f609e5f860..de1ab0267a45f4505b7b3235ba0777bbadf08097 100644 (file)
@@ -176,12 +176,17 @@ func TestOps(t *testing.T) {
                want := val(a[i+3])
                if !eql(got, want) {
                        t.Errorf("%s: got %s; want %s", test, got, want)
+                       continue
                }
+
                if x0 != nil && !eql(x, x0) {
                        t.Errorf("%s: x changed to %s", test, x)
+                       continue
                }
+
                if !eql(y, y0) {
                        t.Errorf("%s: y changed to %s", test, y)
+                       continue
                }
        }
 }
@@ -195,6 +200,69 @@ func eql(x, y Value) bool {
        return Compare(x, token.EQL, y)
 }
 
+// ----------------------------------------------------------------------------
+// String tests
+
+var xxx = strings.Repeat("x", 68)
+
+var stringTests = []struct {
+       input, short, exact string
+}{
+       // Unknown
+       {"", "unknown", "unknown"},
+       {"0x", "unknown", "unknown"},
+       {"'", "unknown", "unknown"},
+       {"1f0", "unknown", "unknown"},
+       {"unknown", "unknown", "unknown"},
+
+       // Bool
+       {"true", "true", "true"},
+       {"false", "false", "false"},
+
+       // String
+       {`""`, `""`, `""`},
+       {`"foo"`, `"foo"`, `"foo"`},
+       {`"` + xxx + `xx"`, `"` + xxx + `xx"`, `"` + xxx + `xx"`},
+       {`"` + xxx + `xxx"`, `"` + xxx + `...`, `"` + xxx + `xxx"`},
+       {`"` + xxx + xxx + `xxx"`, `"` + xxx + `...`, `"` + xxx + xxx + `xxx"`},
+
+       // Int
+       {"0", "0", "0"},
+       {"-1", "-1", "-1"},
+       {"12345", "12345", "12345"},
+       {"-12345678901234567890", "-12345678901234567890", "-12345678901234567890"},
+       {"12345678901234567890", "12345678901234567890", "12345678901234567890"},
+
+       // Float
+       {"0.", "0", "0"},
+       {"-0.0", "0", "0"},
+       {"10.0", "10", "10"},
+       {"2.1", "2.1", "21/10"},
+       {"-2.1", "-2.1", "-21/10"},
+       {"1e9999", "1e+9999", "0x.f8d4a9da224650a8cb2959e10d985ad92adbd44c62917e608b1f24c0e1b76b6f61edffeb15c135a4b601637315f7662f325f82325422b244286a07663c9415d2p+33216"},
+       {"1e-9999", "1e-9999", "0x.83b01ba6d8c0425eec1b21e96f7742d63c2653ed0a024cf8a2f9686df578d7b07d7a83d84df6a2ec70a921d1f6cd5574893a7eda4d28ee719e13a5dce2700759p-33215"},
+       {"2.71828182845904523536028747135266249775724709369995957496696763", "2.71828", "271828182845904523536028747135266249775724709369995957496696763/100000000000000000000000000000000000000000000000000000000000000"},
+
+       // Complex
+       {"0i", "(0 + 0i)", "(0 + 0i)"},
+       {"-0i", "(0 + 0i)", "(0 + 0i)"},
+       {"10i", "(0 + 10i)", "(0 + 10i)"},
+       {"-10i", "(0 + -10i)", "(0 + -10i)"},
+       {"1e9999i", "(0 + 1e+9999i)", "(0 + 0x.f8d4a9da224650a8cb2959e10d985ad92adbd44c62917e608b1f24c0e1b76b6f61edffeb15c135a4b601637315f7662f325f82325422b244286a07663c9415d2p+33216i)"},
+}
+
+func TestString(t *testing.T) {
+       for _, test := range stringTests {
+               x := val(test.input)
+               if got := x.String(); got != test.short {
+                       t.Errorf("%s: got %q; want %q as short string", test.input, got, test.short)
+               }
+               if got := x.ExactString(); got != test.exact {
+                       t.Errorf("%s: got %q; want %q as exact string", test.input, got, test.exact)
+               }
+       }
+}
+
 // ----------------------------------------------------------------------------
 // Support functions
 
@@ -212,6 +280,13 @@ func val(lit string) Value {
                return MakeBool(false)
        }
 
+       if i := strings.IndexByte(lit, '/'); i >= 0 {
+               // assume fraction
+               a := MakeFromLiteral(lit[:i], token.INT, 0)
+               b := MakeFromLiteral(lit[i+1:], token.INT, 0)
+               return BinaryOp(a, token.QUO, b)
+       }
+
        tok := token.INT
        switch first, last := lit[0], lit[len(lit)-1]; {
        case first == '"' || first == '`':
@@ -290,32 +365,29 @@ func doOp(x Value, op token.Token, y Value) (z Value) {
 // Other tests
 
 var fracTests = []string{
-       "0 0 1",
-       "1 1 1",
-       "-1 -1 1",
-       "1.2 6 5",
-       "-0.991 -991 1000",
-       "1e100 1e100 1",
+       "0",
+       "1",
+       "-1",
+       "1.2",
+       "-0.991",
+       "2.718281828",
+       "3.14159265358979323e-10",
+       "1e100",
+       "1e1000",
 }
 
 func TestFractions(t *testing.T) {
        for _, test := range fracTests {
-               a := strings.Split(test, " ")
-               if len(a) != 3 {
-                       t.Errorf("invalid test case: %s", test)
-                       continue
-               }
-
-               x := val(a[0])
-               n := val(a[1])
-               d := val(a[2])
-
-               if got := Num(x); !eql(got, n) {
-                       t.Errorf("%s: got num = %s; want %s", test, got, n)
-               }
-
-               if got := Denom(x); !eql(got, d) {
-                       t.Errorf("%s: got denom = %s; want %s", test, got, d)
+               x := val(test)
+               // We don't check the actual numerator and denominator because they
+               // are unlikely to be 100% correct due to floatVal rounding errors.
+               // Instead, we compute the fraction again and compare the rounded
+               // result.
+               q := BinaryOp(Num(x), token.QUO, Denom(x))
+               got := q.String()
+               want := x.String()
+               if got != want {
+                       t.Errorf("%s: got quotient %s, want %s", x, got, want)
                }
        }
 }
index ed82c47cd99385a634ec3a60fcf8e41fa4b9b8c8..e4e7b7c1c7db945e50fb8d4e9527bfef21426a82 100644 (file)
@@ -18,7 +18,7 @@ import (
 // Internally, we treat functions like methods and collect them in method sets.
 
 // A methodSet describes a set of methods. Entries where Decl == nil are conflict
-// entries (more then one method with the same name at the same embedding level).
+// entries (more than one method with the same name at the same embedding level).
 //
 type methodSet map[string]*Func
 
@@ -71,7 +71,7 @@ func (mset methodSet) set(f *ast.FuncDecl) {
 
 // add adds method m to the method set; m is ignored if the method set
 // already contains a method with the same name at the same or a higher
-// level then m.
+// level than m.
 //
 func (mset methodSet) add(m *Func) {
        old := mset[m.Name]
@@ -151,10 +151,11 @@ type reader struct {
        notes     map[string][]*Note
 
        // declarations
-       imports map[string]int
-       values  []*Value // consts and vars
-       types   map[string]*namedType
-       funcs   methodSet
+       imports   map[string]int
+       hasDotImp bool     // if set, package contains a dot import
+       values    []*Value // consts and vars
+       types     map[string]*namedType
+       funcs     methodSet
 
        // support for package-local error type declarations
        errorDecl bool                 // if set, type "error" was declared locally
@@ -208,7 +209,7 @@ func (r *reader) recordAnonymousField(parent *namedType, fieldType ast.Expr) (fn
 
 func (r *reader) readDoc(comment *ast.CommentGroup) {
        // By convention there should be only one package comment
-       // but collect all of them if there are more then one.
+       // but collect all of them if there are more than one.
        text := comment.Text()
        if r.doc == "" {
                r.doc = text
@@ -471,6 +472,9 @@ func (r *reader) readFile(src *ast.File) {
                                        if s, ok := spec.(*ast.ImportSpec); ok {
                                                if import_, err := strconv.Unquote(s.Path.Value); err == nil {
                                                        r.imports[import_] = 1
+                                                       if s.Name != nil && s.Name.Name == "." {
+                                                               r.hasDotImp = true
+                                                       }
                                                }
                                        }
                                }
@@ -641,11 +645,12 @@ func (r *reader) computeMethodSets() {
 func (r *reader) cleanupTypes() {
        for _, t := range r.types {
                visible := r.isVisible(t.name)
-               if t.decl == nil && (predeclaredTypes[t.name] || t.isEmbedded && visible) {
+               if t.decl == nil && (predeclaredTypes[t.name] || visible && (t.isEmbedded || r.hasDotImp)) {
                        // t.name is a predeclared type (and was not redeclared in this package),
                        // or it was embedded somewhere but its declaration is missing (because
-                       // the AST is incomplete): move any associated values, funcs, and methods
-                       // back to the top-level so that they are not lost.
+                       // the AST is incomplete), or we have a dot-import (and all bets are off):
+                       // move any associated values, funcs, and methods back to the top-level so
+                       // that they are not lost.
                        // 1) move values
                        r.values = append(r.values, t.values...)
                        // 2) move factory functions
diff --git a/libgo/go/go/doc/testdata/issue13742.0.golden b/libgo/go/go/doc/testdata/issue13742.0.golden
new file mode 100644 (file)
index 0000000..8dee9aa
--- /dev/null
@@ -0,0 +1,25 @@
+// 
+PACKAGE issue13742
+
+IMPORTPATH
+       testdata/issue13742
+
+IMPORTS
+       go/ast
+
+FILENAMES
+       testdata/issue13742.go
+
+FUNCTIONS
+       // Both F0 and G0 should appear as functions. 
+       func F0(Node)
+
+       // Both F1 and G1 should appear as functions. 
+       func F1(ast.Node)
+
+       // 
+       func G0() Node
+
+       // 
+       func G1() ast.Node
+
diff --git a/libgo/go/go/doc/testdata/issue13742.1.golden b/libgo/go/go/doc/testdata/issue13742.1.golden
new file mode 100644 (file)
index 0000000..8dee9aa
--- /dev/null
@@ -0,0 +1,25 @@
+// 
+PACKAGE issue13742
+
+IMPORTPATH
+       testdata/issue13742
+
+IMPORTS
+       go/ast
+
+FILENAMES
+       testdata/issue13742.go
+
+FUNCTIONS
+       // Both F0 and G0 should appear as functions. 
+       func F0(Node)
+
+       // Both F1 and G1 should appear as functions. 
+       func F1(ast.Node)
+
+       // 
+       func G0() Node
+
+       // 
+       func G1() ast.Node
+
diff --git a/libgo/go/go/doc/testdata/issue13742.2.golden b/libgo/go/go/doc/testdata/issue13742.2.golden
new file mode 100644 (file)
index 0000000..8dee9aa
--- /dev/null
@@ -0,0 +1,25 @@
+// 
+PACKAGE issue13742
+
+IMPORTPATH
+       testdata/issue13742
+
+IMPORTS
+       go/ast
+
+FILENAMES
+       testdata/issue13742.go
+
+FUNCTIONS
+       // Both F0 and G0 should appear as functions. 
+       func F0(Node)
+
+       // Both F1 and G1 should appear as functions. 
+       func F1(ast.Node)
+
+       // 
+       func G0() Node
+
+       // 
+       func G1() ast.Node
+
diff --git a/libgo/go/go/doc/testdata/issue13742.go b/libgo/go/go/doc/testdata/issue13742.go
new file mode 100644 (file)
index 0000000..dbc1941
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package issue13742
+
+import (
+       "go/ast"
+       . "go/ast"
+)
+
+// Both F0 and G0 should appear as functions.
+func F0(Node)  {}
+func G0() Node { return nil }
+
+// Both F1 and G1 should appear as functions.
+func F1(ast.Node)  {}
+func G1() ast.Node { return nil }
index 1adfd7d45e8450d844b5c3a6184e065c051b555b..b9cacfebd80340bce3ad06007f1e3ac8345b0958 100644 (file)
@@ -12,7 +12,6 @@ import (
        "go/parser"
        "go/printer"
        "go/token"
-       "internal/format"
        "io"
 )
 
@@ -82,7 +81,7 @@ func Node(dst io.Writer, fset *token.FileSet, node interface{}) error {
 //
 func Source(src []byte) ([]byte, error) {
        fset := token.NewFileSet()
-       file, sourceAdj, indentAdj, err := format.Parse(fset, "", src, true)
+       file, sourceAdj, indentAdj, err := parse(fset, "", src, true)
        if err != nil {
                return nil, err
        }
@@ -93,7 +92,7 @@ func Source(src []byte) ([]byte, error) {
                ast.SortImports(fset, file)
        }
 
-       return format.Format(fset, file, sourceAdj, indentAdj, src, config)
+       return format(fset, file, sourceAdj, indentAdj, src, config)
 }
 
 func hasUnsortedImports(file *ast.File) bool {
index 000c611aa25525e318377639cec6b8212a9c9d69..b5817a5dd183ab4b79191f6aca4ab38f27ddf3f1 100644 (file)
@@ -72,6 +72,7 @@ func TestSource(t *testing.T) {
 }
 
 // Test cases that are expected to fail are marked by the prefix "ERROR".
+// The formatted result must look the same as the input for successful tests.
 var tests = []string{
        // declaration lists
        `import "go/format"`,
@@ -91,11 +92,23 @@ var tests = []string{
        "\n\t\t\n\n\t\t\tx := 0\n\t\t\tconst s = `\n\t\tfoo\n`\n\n\n", // no indentation removed inside raw strings
 
        // comments
-       "i := 5 /* Comment */",         // Issue 5551.
-       "\ta()\n//line :1",             // Issue 11276.
-       "\t//xxx\n\ta()\n//line :2",    // Issue 11276.
-       "\ta() //line :1\n\tb()\n",     // Issue 11276.
-       "x := 0\n//line :1\n//line :2", // Issue 11276.
+       "/* Comment */",
+       "\t/* Comment */ ",
+       "\n/* Comment */ ",
+       "i := 5 /* Comment */",         // issue #5551
+       "\ta()\n//line :1",             // issue #11276
+       "\t//xxx\n\ta()\n//line :2",    // issue #11276
+       "\ta() //line :1\n\tb()\n",     // issue #11276
+       "x := 0\n//line :1\n//line :2", // issue #11276
+
+       // whitespace
+       "",     // issue #11275
+       " ",    // issue #11275
+       "\t",   // issue #11275
+       "\t\t", // issue #11275
+       "\n",   // issue #11275
+       "\n\n", // issue #11275
+       "\t\n", // issue #11275
 
        // erroneous programs
        "ERROR1 + 2 +",
similarity index 81%
rename from libgo/go/internal/format/format.go
rename to libgo/go/go/format/internal.go
index a8270ba669a97dfad6f26bc2ed0bd2b908e3b04e..9d04878f8664a1133e7101a7fea723fa6597350d 100644 (file)
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// TODO(gri): This file and the file src/cmd/gofmt/internal.go are
+// the same (but for this comment and the package name). Do not modify
+// one without the other. Determine if we can factor out functionality
+// in a public API. See also #11844 for context.
+
 package format
 
 import (
@@ -13,11 +18,9 @@ import (
        "strings"
 )
 
-const parserMode = parser.ParseComments
-
-// Parse parses src, which was read from the named file,
+// parse parses src, which was read from the named file,
 // as a Go source file, declaration, or statement list.
-func Parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
+func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
        file *ast.File,
        sourceAdj func(src []byte, indent int) []byte,
        indentAdj int,
@@ -85,10 +88,10 @@ func Parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
        return
 }
 
-// Format formats the given package file originally obtained from src
+// format formats the given package file originally obtained from src
 // and adjusts the result based on the original source via sourceAdj
 // and indentAdj.
-func Format(
+func format(
        fset *token.FileSet,
        file *ast.File,
        sourceAdj func(src []byte, indent int) []byte,
@@ -109,7 +112,7 @@ func Format(
        // Partial source file.
        // Determine and prepend leading space.
        i, j := 0, 0
-       for j < len(src) && IsSpace(src[j]) {
+       for j < len(src) && isSpace(src[j]) {
                if src[j] == '\n' {
                        i = j + 1 // byte offset of last line in leading space
                }
@@ -146,18 +149,28 @@ func Format(
        if err != nil {
                return nil, err
        }
-       res = append(res, sourceAdj(buf.Bytes(), cfg.Indent)...)
+       out := sourceAdj(buf.Bytes(), cfg.Indent)
+
+       // If the adjusted output is empty, the source
+       // was empty but (possibly) for white space.
+       // The result is the incoming source.
+       if len(out) == 0 {
+               return src, nil
+       }
+
+       // Otherwise, append output to leading space.
+       res = append(res, out...)
 
        // Determine and append trailing space.
        i = len(src)
-       for i > 0 && IsSpace(src[i-1]) {
+       for i > 0 && isSpace(src[i-1]) {
                i--
        }
        return append(res, src[i:]...), nil
 }
 
-// IsSpace reports whether the byte is a space character.
-// IsSpace defines a space as being among the following bytes: ' ', '\t', '\n' and '\r'.
-func IsSpace(b byte) bool {
+// isSpace reports whether the byte is a space character.
+// isSpace defines a space as being among the following bytes: ' ', '\t', '\n' and '\r'.
+func isSpace(b byte) bool {
        return b == ' ' || b == '\t' || b == '\n' || b == '\r'
 }
index 4590ca30e60155d92cb842ab3745b73ff4a89195..560b853c3915eda87e5be1c1d891b260982cf09c 100644 (file)
@@ -20,31 +20,37 @@ type Lookup func(path string) (io.ReadCloser, error)
 // For returns an Importer for the given compiler and lookup interface,
 // or nil. Supported compilers are "gc", and "gccgo". If lookup is nil,
 // the default package lookup mechanism for the given compiler is used.
+// BUG(issue13847): For does not support non-nil lookup functions.
 func For(compiler string, lookup Lookup) types.Importer {
        switch compiler {
        case "gc":
-               if lookup == nil {
-                       return make(gcimports)
+               if lookup != nil {
+                       panic("gc importer for custom import path lookup not yet implemented")
                }
-               panic("gc importer for custom import path lookup not yet implemented")
+
+               return make(gcimports)
+
        case "gccgo":
                if lookup == nil {
-                       var inst gccgoimporter.GccgoInstallation
-                       if err := inst.InitFromDriver("gccgo"); err != nil {
-                               return nil
-                       }
-                       return &gccgoimports{
-                               packages: make(map[string]*types.Package),
-                               importer: inst.GetImporter(nil, nil),
-                       }
+                       panic("gccgo importer for custom import path lookup not yet implemented")
+               }
+
+               var inst gccgoimporter.GccgoInstallation
+               if err := inst.InitFromDriver("gccgo"); err != nil {
+                       return nil
+               }
+               return &gccgoimports{
+                       packages: make(map[string]*types.Package),
+                       importer: inst.GetImporter(nil, nil),
                }
-               panic("gccgo importer for custom import path lookup not yet implemented")
        }
+
        // compiler not supported
        return nil
 }
 
 // Default returns an Importer for the compiler that built the running binary.
+// If available, the result implements types.ImporterFrom.
 func Default() types.Importer {
        return For(runtime.Compiler, nil)
 }
@@ -54,7 +60,14 @@ func Default() types.Importer {
 type gcimports map[string]*types.Package
 
 func (m gcimports) Import(path string) (*types.Package, error) {
-       return gcimporter.Import(m, path)
+       return m.ImportFrom(path, "" /* no vendoring */, 0)
+}
+
+func (m gcimports) ImportFrom(path, srcDir string, mode types.ImportMode) (*types.Package, error) {
+       if mode != 0 {
+               panic("mode must be 0")
+       }
+       return gcimporter.Import(m, path, srcDir)
 }
 
 // gccgo support
@@ -65,5 +78,13 @@ type gccgoimports struct {
 }
 
 func (m *gccgoimports) Import(path string) (*types.Package, error) {
+       return m.ImportFrom(path, "" /* no vendoring */, 0)
+}
+
+func (m *gccgoimports) ImportFrom(path, srcDir string, mode types.ImportMode) (*types.Package, error) {
+       if mode != 0 {
+               panic("mode must be 0")
+       }
+       // TODO(gri) pass srcDir
        return m.importer(m.packages, path)
 }
index f3bcadbaf77051fbbd9524858ff35e3b58640f6d..c10fa484e391854350732a78149497b82598bc63 100644 (file)
@@ -91,10 +91,10 @@ func runImporterTest(t *testing.T, imp Importer, initmap map[*types.Package]Init
 
 var importerTests = [...]importerTest{
        {pkgpath: "pointer", name: "Int8Ptr", want: "type Int8Ptr *int8"},
-       {pkgpath: "complexnums", name: "NN", want: "const NN untyped complex", wantval: "(-1/1 + -1/1i)"},
-       {pkgpath: "complexnums", name: "NP", want: "const NP untyped complex", wantval: "(-1/1 + 1/1i)"},
-       {pkgpath: "complexnums", name: "PN", want: "const PN untyped complex", wantval: "(1/1 + -1/1i)"},
-       {pkgpath: "complexnums", name: "PP", want: "const PP untyped complex", wantval: "(1/1 + 1/1i)"},
+       {pkgpath: "complexnums", name: "NN", want: "const NN untyped complex", wantval: "(-1 + -1i)"},
+       {pkgpath: "complexnums", name: "NP", want: "const NP untyped complex", wantval: "(-1 + 1i)"},
+       {pkgpath: "complexnums", name: "PN", want: "const PN untyped complex", wantval: "(1 + -1i)"},
+       {pkgpath: "complexnums", name: "PP", want: "const PP untyped complex", wantval: "(1 + 1i)"},
        // TODO: enable this entry once bug has been tracked down
        //{pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import", "math..import"}},
 }
diff --git a/libgo/go/go/internal/gcimporter/bimport.go b/libgo/go/go/internal/gcimporter/bimport.go
new file mode 100644 (file)
index 0000000..6869042
--- /dev/null
@@ -0,0 +1,681 @@
+// Copyright 2015 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 gcimporter
+
+import (
+       "encoding/binary"
+       "fmt"
+       "go/constant"
+       "go/token"
+       "go/types"
+       "sort"
+       "unicode"
+       "unicode/utf8"
+)
+
+// BImportData imports a package from the serialized package data
+// and returns the number of bytes consumed and a reference to the package.
+// If data is obviously malformed, an error is returned but in
+// general it is not recommended to call BImportData on untrusted data.
+func BImportData(imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) {
+       p := importer{
+               imports: imports,
+               data:    data,
+       }
+       p.buf = p.bufarray[:]
+
+       // read low-level encoding format
+       switch format := p.byte(); format {
+       case 'c':
+               // compact format - nothing to do
+       case 'd':
+               p.debugFormat = true
+       default:
+               return p.read, nil, fmt.Errorf("invalid encoding format in export data: got %q; want 'c' or 'd'", format)
+       }
+
+       // --- generic export data ---
+
+       if v := p.string(); v != "v0" {
+               return p.read, nil, fmt.Errorf("unknown version: %s", v)
+       }
+
+       // populate typList with predeclared "known" types
+       p.typList = append(p.typList, predeclared...)
+
+       // read package data
+       // TODO(gri) clean this up
+       i := p.tagOrIndex()
+       if i != packageTag {
+               panic(fmt.Sprintf("package tag expected, got %d", i))
+       }
+       name := p.string()
+       if s := p.string(); s != "" {
+               panic(fmt.Sprintf("empty path expected, got %s", s))
+       }
+       pkg := p.imports[path]
+       if pkg == nil {
+               pkg = types.NewPackage(path, name)
+               p.imports[path] = pkg
+       }
+       p.pkgList = append(p.pkgList, pkg)
+
+       if debug && p.pkgList[0] != pkg {
+               panic("imported packaged not found in pkgList[0]")
+       }
+
+       // read compiler-specific flags
+       p.string() // discard
+
+       // read consts
+       for i := p.int(); i > 0; i-- {
+               name := p.string()
+               typ := p.typ(nil)
+               val := p.value()
+               p.declare(types.NewConst(token.NoPos, pkg, name, typ, val))
+       }
+
+       // read vars
+       for i := p.int(); i > 0; i-- {
+               name := p.string()
+               typ := p.typ(nil)
+               p.declare(types.NewVar(token.NoPos, pkg, name, typ))
+       }
+
+       // read funcs
+       for i := p.int(); i > 0; i-- {
+               name := p.string()
+               sig := p.typ(nil).(*types.Signature)
+               p.int() // read and discard index of inlined function body
+               p.declare(types.NewFunc(token.NoPos, pkg, name, sig))
+       }
+
+       // read types
+       for i := p.int(); i > 0; i-- {
+               // name is parsed as part of named type and the
+               // type object is added to scope via respective
+               // named type
+               _ = p.typ(nil).(*types.Named)
+       }
+
+       // ignore compiler-specific import data
+
+       // complete interfaces
+       for _, typ := range p.typList {
+               if it, ok := typ.(*types.Interface); ok {
+                       it.Complete()
+               }
+       }
+
+       // record all referenced packages as imports
+       list := append(([]*types.Package)(nil), p.pkgList[1:]...)
+       sort.Sort(byPath(list))
+       pkg.SetImports(list)
+
+       // package was imported completely and without errors
+       pkg.MarkComplete()
+
+       return p.read, pkg, nil
+}
+
+type importer struct {
+       imports  map[string]*types.Package
+       data     []byte
+       buf      []byte   // for reading strings
+       bufarray [64]byte // initial underlying array for buf, large enough to avoid allocation when compiling std lib
+       pkgList  []*types.Package
+       typList  []types.Type
+
+       debugFormat bool
+       read        int // bytes read
+}
+
+func (p *importer) declare(obj types.Object) {
+       if alt := p.pkgList[0].Scope().Insert(obj); alt != nil {
+               // This can only happen if we import a package a second time.
+               panic(fmt.Sprintf("%s already declared", alt.Name()))
+       }
+}
+
+func (p *importer) pkg() *types.Package {
+       // if the package was seen before, i is its index (>= 0)
+       i := p.tagOrIndex()
+       if i >= 0 {
+               return p.pkgList[i]
+       }
+
+       // otherwise, i is the package tag (< 0)
+       if i != packageTag {
+               panic(fmt.Sprintf("unexpected package tag %d", i))
+       }
+
+       // read package data
+       name := p.string()
+       path := p.string()
+
+       // we should never see an empty package name
+       if name == "" {
+               panic("empty package name in import")
+       }
+
+       // we should never see an empty import path
+       if path == "" {
+               panic("empty import path")
+       }
+
+       // if the package was imported before, use that one; otherwise create a new one
+       pkg := p.imports[path]
+       if pkg == nil {
+               pkg = types.NewPackage(path, name)
+               p.imports[path] = pkg
+       }
+       p.pkgList = append(p.pkgList, pkg)
+
+       return pkg
+}
+
+func (p *importer) record(t types.Type) {
+       p.typList = append(p.typList, t)
+}
+
+// A dddSlice is a types.Type representing ...T parameters.
+// It only appears for parameter types and does not escape
+// the importer.
+type dddSlice struct {
+       elem types.Type
+}
+
+func (t *dddSlice) Underlying() types.Type { return t }
+func (t *dddSlice) String() string         { return "..." + t.elem.String() }
+
+// parent is the package which declared the type; parent == nil means
+// the package currently imported. The parent package is needed for
+// exported struct fields and interface methods which don't contain
+// explicit package information in the export data.
+func (p *importer) typ(parent *types.Package) types.Type {
+       // if the type was seen before, i is its index (>= 0)
+       i := p.tagOrIndex()
+       if i >= 0 {
+               return p.typList[i]
+       }
+
+       // otherwise, i is the type tag (< 0)
+       switch i {
+       case namedTag:
+               // read type object
+               name := p.string()
+               parent = p.pkg()
+               scope := parent.Scope()
+               obj := scope.Lookup(name)
+
+               // if the object doesn't exist yet, create and insert it
+               if obj == nil {
+                       obj = types.NewTypeName(token.NoPos, parent, name, nil)
+                       scope.Insert(obj)
+               }
+
+               if _, ok := obj.(*types.TypeName); !ok {
+                       panic(fmt.Sprintf("pkg = %s, name = %s => %s", parent, name, obj))
+               }
+
+               // associate new named type with obj if it doesn't exist yet
+               t0 := types.NewNamed(obj.(*types.TypeName), nil, nil)
+
+               // but record the existing type, if any
+               t := obj.Type().(*types.Named)
+               p.record(t)
+
+               // read underlying type
+               t0.SetUnderlying(p.typ(parent))
+
+               // interfaces don't have associated methods
+               if _, ok := t0.Underlying().(*types.Interface); ok {
+                       return t
+               }
+
+               // read associated methods
+               for i := p.int(); i > 0; i-- {
+                       name := p.string()
+                       recv, _ := p.paramList() // TODO(gri) do we need a full param list for the receiver?
+                       params, isddd := p.paramList()
+                       result, _ := p.paramList()
+                       p.int() // read and discard index of inlined function body
+                       sig := types.NewSignature(recv.At(0), params, result, isddd)
+                       t0.AddMethod(types.NewFunc(token.NoPos, parent, name, sig))
+               }
+
+               return t
+
+       case arrayTag:
+               t := new(types.Array)
+               p.record(t)
+
+               n := p.int64()
+               *t = *types.NewArray(p.typ(parent), n)
+               return t
+
+       case sliceTag:
+               t := new(types.Slice)
+               p.record(t)
+
+               *t = *types.NewSlice(p.typ(parent))
+               return t
+
+       case dddTag:
+               t := new(dddSlice)
+               p.record(t)
+
+               t.elem = p.typ(parent)
+               return t
+
+       case structTag:
+               t := new(types.Struct)
+               p.record(t)
+
+               n := p.int()
+               fields := make([]*types.Var, n)
+               tags := make([]string, n)
+               for i := range fields {
+                       fields[i] = p.field(parent)
+                       tags[i] = p.string()
+               }
+               *t = *types.NewStruct(fields, tags)
+               return t
+
+       case pointerTag:
+               t := new(types.Pointer)
+               p.record(t)
+
+               *t = *types.NewPointer(p.typ(parent))
+               return t
+
+       case signatureTag:
+               t := new(types.Signature)
+               p.record(t)
+
+               params, isddd := p.paramList()
+               result, _ := p.paramList()
+               *t = *types.NewSignature(nil, params, result, isddd)
+               return t
+
+       case interfaceTag:
+               // Create a dummy entry in the type list. This is safe because we
+               // cannot expect the interface type to appear in a cycle, as any
+               // such cycle must contain a named type which would have been
+               // first defined earlier.
+               n := len(p.typList)
+               p.record(nil)
+
+               // no embedded interfaces with gc compiler
+               if p.int() != 0 {
+                       panic("unexpected embedded interface")
+               }
+
+               // read methods
+               methods := make([]*types.Func, p.int())
+               for i := range methods {
+                       pkg, name := p.fieldName(parent)
+                       params, isddd := p.paramList()
+                       result, _ := p.paramList()
+                       sig := types.NewSignature(nil, params, result, isddd)
+                       methods[i] = types.NewFunc(token.NoPos, pkg, name, sig)
+               }
+
+               t := types.NewInterface(methods, nil)
+               p.typList[n] = t
+               return t
+
+       case mapTag:
+               t := new(types.Map)
+               p.record(t)
+
+               key := p.typ(parent)
+               val := p.typ(parent)
+               *t = *types.NewMap(key, val)
+               return t
+
+       case chanTag:
+               t := new(types.Chan)
+               p.record(t)
+
+               var dir types.ChanDir
+               // tag values must match the constants in cmd/compile/internal/gc/go.go
+               switch d := p.int(); d {
+               case 1 /* Crecv */ :
+                       dir = types.RecvOnly
+               case 2 /* Csend */ :
+                       dir = types.SendOnly
+               case 3 /* Cboth */ :
+                       dir = types.SendRecv
+               default:
+                       panic(fmt.Sprintf("unexpected channel dir %d", d))
+               }
+               val := p.typ(parent)
+               *t = *types.NewChan(dir, val)
+               return t
+
+       default:
+               panic(fmt.Sprintf("unexpected type tag %d", i))
+       }
+}
+
+func (p *importer) field(parent *types.Package) *types.Var {
+       pkg, name := p.fieldName(parent)
+       typ := p.typ(parent)
+
+       anonymous := false
+       if name == "" {
+               // anonymous field - typ must be T or *T and T must be a type name
+               switch typ := deref(typ).(type) {
+               case *types.Basic: // basic types are named types
+                       pkg = nil // // objects defined in Universe scope have no package
+                       name = typ.Name()
+               case *types.Named:
+                       name = typ.Obj().Name()
+               default:
+                       panic("anonymous field expected")
+               }
+               anonymous = true
+       }
+
+       return types.NewField(token.NoPos, pkg, name, typ, anonymous)
+}
+
+func (p *importer) fieldName(parent *types.Package) (*types.Package, string) {
+       pkg := parent
+       if pkg == nil {
+               // use the imported package instead
+               pkg = p.pkgList[0]
+       }
+       name := p.string()
+       if name == "" {
+               return pkg, "" // anonymous
+       }
+       if name == "?" || name != "_" && !exported(name) {
+               // explicitly qualified field
+               if name == "?" {
+                       name = "" // anonymous
+               }
+               pkg = p.pkg()
+       }
+       return pkg, name
+}
+
+func (p *importer) paramList() (*types.Tuple, bool) {
+       n := p.int()
+       if n == 0 {
+               return nil, false
+       }
+       // negative length indicates unnamed parameters
+       named := true
+       if n < 0 {
+               n = -n
+               named = false
+       }
+       // n > 0
+       params := make([]*types.Var, n)
+       isddd := false
+       for i := range params {
+               params[i], isddd = p.param(named)
+       }
+       return types.NewTuple(params...), isddd
+}
+
+func (p *importer) param(named bool) (*types.Var, bool) {
+       t := p.typ(nil)
+       td, isddd := t.(*dddSlice)
+       if isddd {
+               t = types.NewSlice(td.elem)
+       }
+
+       var name string
+       if named {
+               name = p.string()
+               if name == "" {
+                       panic("expected named parameter")
+               }
+       }
+
+       // read and discard compiler-specific info
+       p.string()
+
+       return types.NewVar(token.NoPos, nil, name, t), isddd
+}
+
+func exported(name string) bool {
+       ch, _ := utf8.DecodeRuneInString(name)
+       return unicode.IsUpper(ch)
+}
+
+func (p *importer) value() constant.Value {
+       switch tag := p.tagOrIndex(); tag {
+       case falseTag:
+               return constant.MakeBool(false)
+       case trueTag:
+               return constant.MakeBool(true)
+       case int64Tag:
+               return constant.MakeInt64(p.int64())
+       case floatTag:
+               return p.float()
+       case complexTag:
+               re := p.float()
+               im := p.float()
+               return constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
+       case stringTag:
+               return constant.MakeString(p.string())
+       default:
+               panic(fmt.Sprintf("unexpected value tag %d", tag))
+       }
+}
+
+func (p *importer) float() constant.Value {
+       sign := p.int()
+       if sign == 0 {
+               return constant.MakeInt64(0)
+       }
+
+       exp := p.int()
+       mant := []byte(p.string()) // big endian
+
+       // remove leading 0's if any
+       for len(mant) > 0 && mant[0] == 0 {
+               mant = mant[1:]
+       }
+
+       // convert to little endian
+       // TODO(gri) go/constant should have a more direct conversion function
+       //           (e.g., once it supports a big.Float based implementation)
+       for i, j := 0, len(mant)-1; i < j; i, j = i+1, j-1 {
+               mant[i], mant[j] = mant[j], mant[i]
+       }
+
+       // adjust exponent (constant.MakeFromBytes creates an integer value,
+       // but mant represents the mantissa bits such that 0.5 <= mant < 1.0)
+       exp -= len(mant) << 3
+       if len(mant) > 0 {
+               for msd := mant[len(mant)-1]; msd&0x80 == 0; msd <<= 1 {
+                       exp++
+               }
+       }
+
+       x := constant.MakeFromBytes(mant)
+       switch {
+       case exp < 0:
+               d := constant.Shift(constant.MakeInt64(1), token.SHL, uint(-exp))
+               x = constant.BinaryOp(x, token.QUO, d)
+       case exp > 0:
+               x = constant.Shift(x, token.SHL, uint(exp))
+       }
+
+       if sign < 0 {
+               x = constant.UnaryOp(token.SUB, x, 0)
+       }
+       return x
+}
+
+// ----------------------------------------------------------------------------
+// Low-level decoders
+
+func (p *importer) tagOrIndex() int {
+       if p.debugFormat {
+               p.marker('t')
+       }
+
+       return int(p.rawInt64())
+}
+
+func (p *importer) int() int {
+       x := p.int64()
+       if int64(int(x)) != x {
+               panic("exported integer too large")
+       }
+       return int(x)
+}
+
+func (p *importer) int64() int64 {
+       if p.debugFormat {
+               p.marker('i')
+       }
+
+       return p.rawInt64()
+}
+
+func (p *importer) string() string {
+       if p.debugFormat {
+               p.marker('s')
+       }
+
+       if n := int(p.rawInt64()); n > 0 {
+               if cap(p.buf) < n {
+                       p.buf = make([]byte, n)
+               } else {
+                       p.buf = p.buf[:n]
+               }
+               for i := 0; i < n; i++ {
+                       p.buf[i] = p.byte()
+               }
+               return string(p.buf)
+       }
+
+       return ""
+}
+
+func (p *importer) marker(want byte) {
+       if got := p.byte(); got != want {
+               panic(fmt.Sprintf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read))
+       }
+
+       pos := p.read
+       if n := int(p.rawInt64()); n != pos {
+               panic(fmt.Sprintf("incorrect position: got %d; want %d", n, pos))
+       }
+}
+
+// rawInt64 should only be used by low-level decoders
+func (p *importer) rawInt64() int64 {
+       i, err := binary.ReadVarint(p)
+       if err != nil {
+               panic(fmt.Sprintf("read error: %v", err))
+       }
+       return i
+}
+
+// needed for binary.ReadVarint in rawInt64
+func (p *importer) ReadByte() (byte, error) {
+       return p.byte(), nil
+}
+
+// byte is the bottleneck interface for reading p.data.
+// It unescapes '|' 'S' to '$' and '|' '|' to '|'.
+func (p *importer) byte() byte {
+       b := p.data[0]
+       r := 1
+       if b == '|' {
+               b = p.data[1]
+               r = 2
+               switch b {
+               case 'S':
+                       b = '$'
+               case '|':
+                       // nothing to do
+               default:
+                       panic("unexpected escape sequence in export data")
+               }
+       }
+       p.data = p.data[r:]
+       p.read += r
+       return b
+
+}
+
+// ----------------------------------------------------------------------------
+// Export format
+
+// Tags. Must be < 0.
+const (
+       // Packages
+       packageTag = -(iota + 1)
+
+       // Types
+       namedTag
+       arrayTag
+       sliceTag
+       dddTag
+       structTag
+       pointerTag
+       signatureTag
+       interfaceTag
+       mapTag
+       chanTag
+
+       // Values
+       falseTag
+       trueTag
+       int64Tag
+       floatTag
+       fractionTag // not used by gc
+       complexTag
+       stringTag
+)
+
+var predeclared = []types.Type{
+       // basic types
+       types.Typ[types.Bool],
+       types.Typ[types.Int],
+       types.Typ[types.Int8],
+       types.Typ[types.Int16],
+       types.Typ[types.Int32],
+       types.Typ[types.Int64],
+       types.Typ[types.Uint],
+       types.Typ[types.Uint8],
+       types.Typ[types.Uint16],
+       types.Typ[types.Uint32],
+       types.Typ[types.Uint64],
+       types.Typ[types.Uintptr],
+       types.Typ[types.Float32],
+       types.Typ[types.Float64],
+       types.Typ[types.Complex64],
+       types.Typ[types.Complex128],
+       types.Typ[types.String],
+
+       // aliases
+       types.Universe.Lookup("byte").Type(),
+       types.Universe.Lookup("rune").Type(),
+
+       // error
+       types.Universe.Lookup("error").Type(),
+
+       // untyped types
+       types.Typ[types.UntypedBool],
+       types.Typ[types.UntypedInt],
+       types.Typ[types.UntypedRune],
+       types.Typ[types.UntypedFloat],
+       types.Typ[types.UntypedComplex],
+       types.Typ[types.UntypedString],
+       types.Typ[types.UntypedNil],
+
+       // package unsafe
+       types.Typ[types.UnsafePointer],
+}
index 657742bb6d79dc9f3d852e1f7e05102aaa618f4a..18bea415ae49695174ab95be4dc2dec72cacf897 100644 (file)
@@ -39,14 +39,16 @@ func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
 // FindExportData positions the reader r at the beginning of the
 // export data section of an underlying GC-created object/archive
 // file by reading from it. The reader must be positioned at the
-// start of the file before calling this function.
+// start of the file before calling this function. The hdr result
+// is the string before the export data, either "$$" or "$$B".
 //
-func FindExportData(r *bufio.Reader) (err error) {
+func FindExportData(r *bufio.Reader) (hdr string, err error) {
        // Read first line to make sure this is an object file.
        line, err := r.ReadSlice('\n')
        if err != nil {
                return
        }
+
        if string(line) == "!<arch>\n" {
                // Archive file. Scan to __.PKGDEF.
                var name string
@@ -71,7 +73,7 @@ func FindExportData(r *bufio.Reader) (err error) {
                                size -= n
                        }
 
-                       if name, size, err = readGopackHeader(r); err != nil {
+                       if name, _, err = readGopackHeader(r); err != nil {
                                return
                        }
                }
@@ -97,12 +99,13 @@ func FindExportData(r *bufio.Reader) (err error) {
        }
 
        // Skip over object header to export data.
-       // Begins after first line with $$.
+       // Begins after first line starting with $$.
        for line[0] != '$' {
                if line, err = r.ReadSlice('\n'); err != nil {
                        return
                }
        }
+       hdr = string(line)
 
        return
 }
index 1d485cf9cbf4aafc9330280874c916487289fda5..0ef8eb4fc6ca78bf65f81c0326ad4745e49b20a6 100644 (file)
@@ -12,6 +12,7 @@ import (
        "go/build"
        "go/token"
        "io"
+       "io/ioutil"
        "os"
        "path/filepath"
        "sort"
@@ -34,11 +35,10 @@ var pkgExts = [...]string{".a", ".o"}
 // If no file was found, an empty filename is returned.
 //
 func FindPkg(path, srcDir string) (filename, id string) {
-       if len(path) == 0 {
+       if path == "" {
                return
        }
 
-       id = path
        var noext string
        switch {
        default:
@@ -49,6 +49,7 @@ func FindPkg(path, srcDir string) (filename, id string) {
                        return
                }
                noext = strings.TrimSuffix(bp.PkgObj, ".a")
+               id = bp.ImportPath
 
        case build.IsLocalImport(path):
                // "./x" -> "/this/directory/x.ext", "/this/directory/x"
@@ -60,6 +61,13 @@ func FindPkg(path, srcDir string) (filename, id string) {
                // does not support absolute imports
                // "/x" -> "/x.ext", "/x"
                noext = path
+               id = path
+       }
+
+       if false { // for debugging
+               if path != id {
+                       fmt.Printf("%s -> %s\n", path, id)
+               }
        }
 
        // try extensions
@@ -106,27 +114,16 @@ func ImportData(packages map[string]*types.Package, filename, id string, data io
        return
 }
 
-// Import imports a gc-generated package given its import path, adds the
-// corresponding package object to the packages map, and returns the object.
-// Local import paths are interpreted relative to the current working directory.
+// Import imports a gc-generated package given its import path and srcDir, adds
+// the corresponding package object to the packages map, and returns the object.
 // The packages map must contain all packages already imported.
 //
-func Import(packages map[string]*types.Package, path string) (pkg *types.Package, err error) {
-       // package "unsafe" is handled by the type checker
-       if path == "unsafe" {
-               panic(`gcimporter.Import called for package "unsafe"`)
-       }
-
-       srcDir := "."
-       if build.IsLocalImport(path) {
-               srcDir, err = os.Getwd()
-               if err != nil {
-                       return
-               }
-       }
-
+func Import(packages map[string]*types.Package, path, srcDir string) (pkg *types.Package, err error) {
        filename, id := FindPkg(path, srcDir)
        if filename == "" {
+               if path == "unsafe" {
+                       return types.Unsafe, nil
+               }
                err = fmt.Errorf("can't find import: %s", id)
                return
        }
@@ -149,12 +146,25 @@ func Import(packages map[string]*types.Package, path string) (pkg *types.Package
                }
        }()
 
+       var hdr string
        buf := bufio.NewReader(f)
-       if err = FindExportData(buf); err != nil {
+       if hdr, err = FindExportData(buf); err != nil {
                return
        }
 
-       pkg, err = ImportData(packages, filename, id, buf)
+       switch hdr {
+       case "$$\n":
+               return ImportData(packages, filename, id, buf)
+       case "$$B\n":
+               var data []byte
+               data, err = ioutil.ReadAll(buf)
+               if err == nil {
+                       _, pkg, err = BImportData(packages, data, path)
+                       return
+               }
+       default:
+               err = fmt.Errorf("unknown export data header: %q", hdr)
+       }
 
        return
 }
@@ -335,8 +345,10 @@ func (p *parser) parseQualifiedName() (id, name string) {
 }
 
 // getPkg returns the package for a given id. If the package is
-// not found but we have a package name, create the package and
-// add it to the p.localPkgs and p.sharedPkgs maps.
+// not found, create the package and add it to the p.localPkgs
+// and p.sharedPkgs maps. name is the (expected) name of the
+// package. If name == "", the package name is expected to be
+// set later via an import clause in the export data.
 //
 // id identifies a package, usually by a canonical package path like
 // "encoding/json" but possibly by a non-canonical import path like
@@ -349,19 +361,28 @@ func (p *parser) getPkg(id, name string) *types.Package {
        }
 
        pkg := p.localPkgs[id]
-       if pkg == nil && name != "" {
+       if pkg == nil {
                // first import of id from this package
                pkg = p.sharedPkgs[id]
                if pkg == nil {
-                       // first import of id by this importer
+                       // first import of id by this importer;
+                       // add (possibly unnamed) pkg to shared packages
                        pkg = types.NewPackage(id, name)
                        p.sharedPkgs[id] = pkg
                }
-
+               // add (possibly unnamed) pkg to local packages
                if p.localPkgs == nil {
                        p.localPkgs = make(map[string]*types.Package)
                }
                p.localPkgs[id] = pkg
+       } else if name != "" {
+               // package exists already and we have an expected package name;
+               // make sure names match or set package name if necessary
+               if pname := pkg.Name(); pname == "" {
+                       pkg.SetName(name)
+               } else if pname != name {
+                       p.errorf("%s package name mismatch: %s (given) vs %s (expected)", pname, name)
+               }
        }
        return pkg
 }
@@ -372,9 +393,6 @@ func (p *parser) getPkg(id, name string) *types.Package {
 func (p *parser) parseExportedName() (pkg *types.Package, name string) {
        id, name := p.parseQualifiedName()
        pkg = p.getPkg(id, "")
-       if pkg == nil {
-               p.errorf("%s package not found", id)
-       }
        return
 }
 
@@ -395,11 +413,11 @@ func (p *parser) parseBasicType() types.Type {
 
 // ArrayType = "[" int_lit "]" Type .
 //
-func (p *parser) parseArrayType() types.Type {
+func (p *parser) parseArrayType(parent *types.Package) types.Type {
        // "[" already consumed and lookahead known not to be "]"
        lit := p.expect(scanner.Int)
        p.expect(']')
-       elem := p.parseType()
+       elem := p.parseType(parent)
        n, err := strconv.ParseInt(lit, 10, 64)
        if err != nil {
                p.error(err)
@@ -409,46 +427,47 @@ func (p *parser) parseArrayType() types.Type {
 
 // MapType = "map" "[" Type "]" Type .
 //
-func (p *parser) parseMapType() types.Type {
+func (p *parser) parseMapType(parent *types.Package) types.Type {
        p.expectKeyword("map")
        p.expect('[')
-       key := p.parseType()
+       key := p.parseType(parent)
        p.expect(']')
-       elem := p.parseType()
+       elem := p.parseType(parent)
        return types.NewMap(key, elem)
 }
 
 // Name = identifier | "?" | QualifiedName .
 //
-// If materializePkg is set, the returned package is guaranteed to be set.
-// For fully qualified names, the returned package may be a fake package
-// (without name, scope, and not in the p.sharedPkgs map), created for the
-// sole purpose of providing a package path. Fake packages are created
-// when the package id is not found in the p.sharedPkgs map; in that case
-// we cannot create a real package because we don't have a package name.
-// For non-qualified names, the returned package is the imported package.
+// For unqualified and anonymous names, the returned package is the parent
+// package unless parent == nil, in which case the returned package is the
+// package being imported. (The parent package is not nil if the the name
+// is an unqualified struct field or interface method name belonging to a
+// type declared in another package.)
+//
+// For qualified names, the returned package is nil (and not created if
+// it doesn't exist yet) unless materializePkg is set (which creates an
+// unnamed package with valid package path). In the latter case, a
+// subequent import clause is expected to provide a name for the package.
 //
-func (p *parser) parseName(materializePkg bool) (pkg *types.Package, name string) {
+func (p *parser) parseName(parent *types.Package, materializePkg bool) (pkg *types.Package, name string) {
+       pkg = parent
+       if pkg == nil {
+               pkg = p.sharedPkgs[p.id]
+       }
        switch p.tok {
        case scanner.Ident:
-               pkg = p.sharedPkgs[p.id]
                name = p.lit
                p.next()
        case '?':
                // anonymous
-               pkg = p.sharedPkgs[p.id]
                p.next()
        case '@':
                // exported name prefixed with package path
+               pkg = nil
                var id string
                id, name = p.parseQualifiedName()
                if materializePkg {
-                       // we don't have a package name - if the package
-                       // doesn't exist yet, create a fake package instead
                        pkg = p.getPkg(id, "")
-                       if pkg == nil {
-                               pkg = types.NewPackage(id, "")
-                       }
                }
        default:
                p.error("name expected")
@@ -465,15 +484,15 @@ func deref(typ types.Type) types.Type {
 
 // Field = Name Type [ string_lit ] .
 //
-func (p *parser) parseField() (*types.Var, string) {
-       pkg, name := p.parseName(true)
-       typ := p.parseType()
+func (p *parser) parseField(parent *types.Package) (*types.Var, string) {
+       pkg, name := p.parseName(parent, true)
+       typ := p.parseType(parent)
        anonymous := false
        if name == "" {
                // anonymous field - typ must be T or *T and T must be a type name
                switch typ := deref(typ).(type) {
                case *types.Basic: // basic types are named types
-                       pkg = nil
+                       pkg = nil // objects defined in Universe scope have no package
                        name = typ.Name()
                case *types.Named:
                        name = typ.Obj().Name()
@@ -497,7 +516,7 @@ func (p *parser) parseField() (*types.Var, string) {
 // StructType = "struct" "{" [ FieldList ] "}" .
 // FieldList  = Field { ";" Field } .
 //
-func (p *parser) parseStructType() types.Type {
+func (p *parser) parseStructType(parent *types.Package) types.Type {
        var fields []*types.Var
        var tags []string
 
@@ -507,7 +526,7 @@ func (p *parser) parseStructType() types.Type {
                if i > 0 {
                        p.expect(';')
                }
-               fld, tag := p.parseField()
+               fld, tag := p.parseField(parent)
                if tag != "" && tags == nil {
                        tags = make([]string, i)
                }
@@ -524,7 +543,7 @@ func (p *parser) parseStructType() types.Type {
 // Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] .
 //
 func (p *parser) parseParameter() (par *types.Var, isVariadic bool) {
-       _, name := p.parseName(false)
+       _, name := p.parseName(nil, false)
        // remove gc-specific parameter numbering
        if i := strings.Index(name, "·"); i >= 0 {
                name = name[:i]
@@ -533,7 +552,7 @@ func (p *parser) parseParameter() (par *types.Var, isVariadic bool) {
                p.expectSpecial("...")
                isVariadic = true
        }
-       typ := p.parseType()
+       typ := p.parseType(nil)
        if isVariadic {
                typ = types.NewSlice(typ)
        }
@@ -596,7 +615,7 @@ func (p *parser) parseSignature(recv *types.Var) *types.Signature {
 // by the compiler and thus embedded interfaces are never
 // visible in the export data.
 //
-func (p *parser) parseInterfaceType() types.Type {
+func (p *parser) parseInterfaceType(parent *types.Package) types.Type {
        var methods []*types.Func
 
        p.expectKeyword("interface")
@@ -605,7 +624,7 @@ func (p *parser) parseInterfaceType() types.Type {
                if i > 0 {
                        p.expect(';')
                }
-               pkg, name := p.parseName(true)
+               pkg, name := p.parseName(parent, true)
                sig := p.parseSignature(nil)
                methods = append(methods, types.NewFunc(token.NoPos, pkg, name, sig))
        }
@@ -618,7 +637,7 @@ func (p *parser) parseInterfaceType() types.Type {
 
 // ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
 //
-func (p *parser) parseChanType() types.Type {
+func (p *parser) parseChanType(parent *types.Package) types.Type {
        dir := types.SendRecv
        if p.tok == scanner.Ident {
                p.expectKeyword("chan")
@@ -631,7 +650,7 @@ func (p *parser) parseChanType() types.Type {
                p.expectKeyword("chan")
                dir = types.RecvOnly
        }
-       elem := p.parseType()
+       elem := p.parseType(parent)
        return types.NewChan(dir, elem)
 }
 
@@ -646,24 +665,24 @@ func (p *parser) parseChanType() types.Type {
 // PointerType = "*" Type .
 // FuncType    = "func" Signature .
 //
-func (p *parser) parseType() types.Type {
+func (p *parser) parseType(parent *types.Package) types.Type {
        switch p.tok {
        case scanner.Ident:
                switch p.lit {
                default:
                        return p.parseBasicType()
                case "struct":
-                       return p.parseStructType()
+                       return p.parseStructType(parent)
                case "func":
                        // FuncType
                        p.next()
                        return p.parseSignature(nil)
                case "interface":
-                       return p.parseInterfaceType()
+                       return p.parseInterfaceType(parent)
                case "map":
-                       return p.parseMapType()
+                       return p.parseMapType(parent)
                case "chan":
-                       return p.parseChanType()
+                       return p.parseChanType(parent)
                }
        case '@':
                // TypeName
@@ -674,19 +693,19 @@ func (p *parser) parseType() types.Type {
                if p.tok == ']' {
                        // SliceType
                        p.next()
-                       return types.NewSlice(p.parseType())
+                       return types.NewSlice(p.parseType(parent))
                }
-               return p.parseArrayType()
+               return p.parseArrayType(parent)
        case '*':
                // PointerType
                p.next()
-               return types.NewPointer(p.parseType())
+               return types.NewPointer(p.parseType(parent))
        case '<':
-               return p.parseChanType()
+               return p.parseChanType(parent)
        case '(':
                // "(" Type ")"
                p.next()
-               typ := p.parseType()
+               typ := p.parseType(parent)
                p.expect(')')
                return typ
        }
@@ -768,7 +787,8 @@ func (p *parser) parseConstDecl() {
 
        var typ0 types.Type
        if p.tok != '=' {
-               typ0 = p.parseType()
+               // constant types are never structured - no need for parent type
+               typ0 = p.parseType(nil)
        }
 
        p.expect('=')
@@ -842,7 +862,7 @@ func (p *parser) parseTypeDecl() {
        // structure, but throw it away if the object already has a type.
        // This ensures that all imports refer to the same type object for
        // a given type declaration.
-       typ := p.parseType()
+       typ := p.parseType(pkg)
 
        if name := obj.Type().(*types.Named); name.Underlying() == nil {
                name.SetUnderlying(typ)
@@ -854,7 +874,7 @@ func (p *parser) parseTypeDecl() {
 func (p *parser) parseVarDecl() {
        p.expectKeyword("var")
        pkg, name := p.parseExportedName()
-       typ := p.parseType()
+       typ := p.parseType(pkg)
        pkg.Scope().Insert(types.NewVar(token.NoPos, pkg, name, typ))
 }
 
@@ -890,7 +910,7 @@ func (p *parser) parseMethodDecl() {
        base := deref(recv.Type()).(*types.Named)
 
        // parse method name, signature, and possibly inlined body
-       _, name := p.parseName(true)
+       _, name := p.parseName(nil, false)
        sig := p.parseFunc(recv)
 
        // methods always belong to the same package as the base type object
@@ -967,9 +987,12 @@ func (p *parser) parseExport() *types.Package {
                p.errorf("expected no scanner errors, got %d", n)
        }
 
-       // Record all referenced packages as imports.
+       // Record all locally referenced packages as imports.
        var imports []*types.Package
        for id, pkg2 := range p.localPkgs {
+               if pkg2.Name() == "" {
+                       p.errorf("%s package has no name", id)
+               }
                if id == p.id {
                        continue // avoid self-edge
                }
index 07993a801f7e7c28c462c637b12f26e92fda0eb0..e56720b0d525435215a4dcd9e66f915d5d024d49 100644 (file)
@@ -46,13 +46,23 @@ func compile(t *testing.T, dirname, filename string) string {
        return filepath.Join(dirname, filename[:len(filename)-2]+"o")
 }
 
-// Use the same global imports map for all tests. The effect is
-// as if all tested packages were imported into a single package.
-var imports = make(map[string]*types.Package)
+// TODO(gri) Remove this function once we switched to new export format by default.
+func compileNewExport(t *testing.T, dirname, filename string) string {
+       testenv.MustHaveGoBuild(t)
+       cmd := exec.Command("go", "tool", "compile", "-newexport", filename)
+       cmd.Dir = dirname
+       out, err := cmd.CombinedOutput()
+       if err != nil {
+               t.Logf("%s", out)
+               t.Fatalf("go tool compile %s failed: %s", filename, err)
+       }
+       // filename should end with ".go"
+       return filepath.Join(dirname, filename[:len(filename)-2]+"o")
+}
 
-func testPath(t *testing.T, path string) *types.Package {
+func testPath(t *testing.T, path, srcDir string) *types.Package {
        t0 := time.Now()
-       pkg, err := Import(imports, path)
+       pkg, err := Import(make(map[string]*types.Package), path, srcDir)
        if err != nil {
                t.Errorf("testPath(%s): %s", path, err)
                return nil
@@ -80,7 +90,7 @@ func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) {
                        for _, ext := range pkgExts {
                                if strings.HasSuffix(f.Name(), ext) {
                                        name := f.Name()[0 : len(f.Name())-len(ext)] // remove extension
-                                       if testPath(t, filepath.Join(dir, name)) != nil {
+                                       if testPath(t, filepath.Join(dir, name), dir) != nil {
                                                nimports++
                                        }
                                }
@@ -92,7 +102,7 @@ func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) {
        return
 }
 
-func TestImport(t *testing.T) {
+func TestImportTestdata(t *testing.T) {
        // This package only handles gc export data.
        if runtime.Compiler != "gc" {
                t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
@@ -103,20 +113,62 @@ func TestImport(t *testing.T) {
                defer os.Remove(outFn)
        }
 
-       nimports := 0
-       if pkg := testPath(t, "./testdata/exports"); pkg != nil {
-               nimports++
-               // The package's Imports should include all the types
-               // referenced by the exportdata, which may be more than
-               // the import statements in the package's source, but
-               // fewer than the transitive closure of dependencies.
-               want := `[package ast ("go/ast") package token ("go/token") package runtime ("runtime")]`
+       if pkg := testPath(t, "./testdata/exports", "."); pkg != nil {
+               // The package's Imports list must include all packages
+               // explicitly imported by exports.go, plus all packages
+               // referenced indirectly via exported objects in exports.go.
+               // With the textual export format, the list may also include
+               // additional packages that are not strictly required for
+               // import processing alone (they are exported to err "on
+               // the safe side").
+               got := fmt.Sprint(pkg.Imports())
+               for _, want := range []string{"go/ast", "go/token"} {
+                       if !strings.Contains(got, want) {
+                               t.Errorf(`Package("exports").Imports() = %s, does not contain %s`, got, want)
+                       }
+               }
+       }
+}
+
+// TODO(gri) Remove this function once we switched to new export format by default
+//           (and update the comment and want list in TestImportTestdata).
+func TestImportTestdataNewExport(t *testing.T) {
+       // This package only handles gc export data.
+       if runtime.Compiler != "gc" {
+               t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+               return
+       }
+
+       if outFn := compileNewExport(t, "testdata", "exports.go"); outFn != "" {
+               defer os.Remove(outFn)
+       }
+
+       if pkg := testPath(t, "./testdata/exports", "."); pkg != nil {
+               // The package's Imports list must include all packages
+               // explicitly imported by exports.go, plus all packages
+               // referenced indirectly via exported objects in exports.go.
+               want := `[package ast ("go/ast") package token ("go/token")]`
                got := fmt.Sprint(pkg.Imports())
                if got != want {
                        t.Errorf(`Package("exports").Imports() = %s, want %s`, got, want)
                }
        }
-       nimports += testDir(t, "", time.Now().Add(maxTime)) // installed packages
+}
+
+func TestImportStdLib(t *testing.T) {
+       skipSpecialPlatforms(t)
+
+       // This package only handles gc export data.
+       if runtime.Compiler != "gc" {
+               t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+               return
+       }
+
+       dt := maxTime
+       if testing.Short() && testenv.Builder() == "" {
+               dt = 10 * time.Millisecond
+       }
+       nimports := testDir(t, "", time.Now().Add(dt)) // installed packages
        t.Logf("tested %d imports", nimports)
 }
 
@@ -148,7 +200,7 @@ func TestImportedTypes(t *testing.T) {
                importPath := s[0]
                objName := s[1]
 
-               pkg, err := Import(imports, importPath)
+               pkg, err := Import(make(map[string]*types.Package), importPath, ".")
                if err != nil {
                        t.Error(err)
                        continue
@@ -176,7 +228,7 @@ func TestIssue5815(t *testing.T) {
                return
        }
 
-       pkg, err := Import(make(map[string]*types.Package), "strings")
+       pkg, err := Import(make(map[string]*types.Package), "strings", ".")
        if err != nil {
                t.Fatal(err)
        }
@@ -210,7 +262,7 @@ func TestCorrectMethodPackage(t *testing.T) {
        }
 
        imports := make(map[string]*types.Package)
-       _, err := Import(imports, "net/http")
+       _, err := Import(imports, "net/http", ".")
        if err != nil {
                t.Fatal(err)
        }
@@ -223,3 +275,89 @@ func TestCorrectMethodPackage(t *testing.T) {
                t.Errorf("got package path %q; want %q", got, want)
        }
 }
+
+func TestIssue13566(t *testing.T) {
+       skipSpecialPlatforms(t)
+
+       // This package only handles gc export data.
+       if runtime.Compiler != "gc" {
+               t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+               return
+       }
+
+       // On windows, we have to set the -D option for the compiler to avoid having a drive
+       // letter and an illegal ':' in the import path - just skip it (see also issue #3483).
+       if runtime.GOOS == "windows" {
+               t.Skip("avoid dealing with relative paths/drive letters on windows")
+       }
+
+       if f := compile(t, "testdata", "a.go"); f != "" {
+               defer os.Remove(f)
+       }
+       if f := compile(t, "testdata", "b.go"); f != "" {
+               defer os.Remove(f)
+       }
+
+       // import must succeed (test for issue at hand)
+       pkg, err := Import(make(map[string]*types.Package), "./testdata/b", ".")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       // make sure all indirectly imported packages have names
+       for _, imp := range pkg.Imports() {
+               if imp.Name() == "" {
+                       t.Errorf("no name for %s package", imp.Path())
+               }
+       }
+}
+
+func TestIssue13898(t *testing.T) {
+       skipSpecialPlatforms(t)
+
+       // This package only handles gc export data.
+       if runtime.Compiler != "gc" {
+               t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+               return
+       }
+
+       // import go/internal/gcimporter which imports go/types partially
+       imports := make(map[string]*types.Package)
+       _, err := Import(imports, "go/internal/gcimporter", ".")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       // look for go/types package
+       var goTypesPkg *types.Package
+       for path, pkg := range imports {
+               if path == "go/types" {
+                       goTypesPkg = pkg
+                       break
+               }
+       }
+       if goTypesPkg == nil {
+               t.Fatal("go/types not found")
+       }
+
+       // look for go/types.Object type
+       obj := goTypesPkg.Scope().Lookup("Object")
+       if obj == nil {
+               t.Fatal("go/types.Object not found")
+       }
+       typ, ok := obj.Type().(*types.Named)
+       if !ok {
+               t.Fatalf("go/types.Object type is %v; wanted named type", typ)
+       }
+
+       // lookup go/types.Object.Pkg method
+       m, _, _ := types.LookupFieldOrMethod(typ, false, nil, "Pkg")
+       if m == nil {
+               t.Fatal("go/types.Object.Pkg not found")
+       }
+
+       // the method must belong to go/types
+       if m.Pkg().Path() != "go/types" {
+               t.Fatalf("found %v; want go/types", m.Pkg())
+       }
+}
diff --git a/libgo/go/go/internal/gcimporter/testdata/a.go b/libgo/go/go/internal/gcimporter/testdata/a.go
new file mode 100644 (file)
index 0000000..56e4292
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Input for TestIssue13566
+
+package a
+
+import "encoding/json"
+
+type A struct {
+       a    *A
+       json json.RawMessage
+}
diff --git a/libgo/go/go/internal/gcimporter/testdata/b.go b/libgo/go/go/internal/gcimporter/testdata/b.go
new file mode 100644 (file)
index 0000000..4196678
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Input for TestIssue13566
+
+package b
+
+import "./a"
+
+type A a.A
index e82c0bd12231e6763d1627774d0390dc34514942..f3a26032eec448100159fd0255201158019d2aff 100644 (file)
@@ -410,9 +410,14 @@ func (p *parser) expectClosing(tok token.Token, context string) token.Pos {
 func (p *parser) expectSemi() {
        // semicolon is optional before a closing ')' or '}'
        if p.tok != token.RPAREN && p.tok != token.RBRACE {
-               if p.tok == token.SEMICOLON {
+               switch p.tok {
+               case token.COMMA:
+                       // permit a ',' instead of a ';' but complain
+                       p.errorExpected(p.pos, "';'")
+                       fallthrough
+               case token.SEMICOLON:
                        p.next()
-               } else {
+               default:
                        p.errorExpected(p.pos, "';'")
                        syncStmt(p)
                }
@@ -690,16 +695,19 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
 
        doc := p.leadComment
 
-       // FieldDecl
-       list, typ := p.parseVarList(false)
-
-       // Tag
-       var tag *ast.BasicLit
-       if p.tok == token.STRING {
-               tag = &ast.BasicLit{ValuePos: p.pos, Kind: p.tok, Value: p.lit}
+       // 1st FieldDecl
+       // A type name used as an anonymous field looks like a field identifier.
+       var list []ast.Expr
+       for {
+               list = append(list, p.parseVarType(false))
+               if p.tok != token.COMMA {
+                       break
+               }
                p.next()
        }
 
+       typ := p.tryVarType(false)
+
        // analyze case
        var idents []*ast.Ident
        if typ != nil {
@@ -708,13 +716,22 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
        } else {
                // ["*"] TypeName (AnonymousField)
                typ = list[0] // we always have at least one element
-               if n := len(list); n > 1 || !isTypeName(deref(typ)) {
-                       pos := typ.Pos()
-                       p.errorExpected(pos, "anonymous field")
-                       typ = &ast.BadExpr{From: pos, To: p.safePos(list[n-1].End())}
+               if n := len(list); n > 1 {
+                       p.errorExpected(p.pos, "type")
+                       typ = &ast.BadExpr{From: p.pos, To: p.pos}
+               } else if !isTypeName(deref(typ)) {
+                       p.errorExpected(typ.Pos(), "anonymous field")
+                       typ = &ast.BadExpr{From: typ.Pos(), To: p.safePos(typ.End())}
                }
        }
 
+       // Tag
+       var tag *ast.BasicLit
+       if p.tok == token.STRING {
+               tag = &ast.BasicLit{ValuePos: p.pos, Kind: p.tok, Value: p.lit}
+               p.next()
+       }
+
        p.expectSemi() // call before accessing p.linecomment
 
        field := &ast.Field{Doc: doc, Names: idents, Type: typ, Tag: tag, Comment: p.lineComment}
@@ -791,42 +808,27 @@ func (p *parser) parseVarType(isParam bool) ast.Expr {
        return typ
 }
 
-// If any of the results are identifiers, they are not resolved.
-func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
+func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params []*ast.Field) {
        if p.trace {
-               defer un(trace(p, "VarList"))
+               defer un(trace(p, "ParameterList"))
        }
 
-       // a list of identifiers looks like a list of type names
-       //
-       // parse/tryVarType accepts any type (including parenthesized
-       // ones) even though the syntax does not permit them here: we
-       // accept them all for more robust parsing and complain later
-       for typ := p.parseVarType(isParam); typ != nil; {
-               list = append(list, typ)
+       // 1st ParameterDecl
+       // A list of identifiers looks like a list of type names.
+       var list []ast.Expr
+       for {
+               list = append(list, p.parseVarType(ellipsisOk))
                if p.tok != token.COMMA {
                        break
                }
                p.next()
-               typ = p.tryVarType(isParam) // maybe nil as in: func f(int,) {}
-       }
-
-       // if we had a list of identifiers, it must be followed by a type
-       typ = p.tryVarType(isParam)
-
-       return
-}
-
-func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params []*ast.Field) {
-       if p.trace {
-               defer un(trace(p, "ParameterList"))
+               if p.tok == token.RPAREN {
+                       break
+               }
        }
 
-       // ParameterDecl
-       list, typ := p.parseVarList(ellipsisOk)
-
        // analyze case
-       if typ != nil {
+       if typ := p.tryVarType(ellipsisOk); typ != nil {
                // IdentifierList Type
                idents := p.makeIdentList(list)
                field := &ast.Field{Names: idents, Type: typ}
@@ -1855,7 +1857,16 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
        var else_ ast.Stmt
        if p.tok == token.ELSE {
                p.next()
-               else_ = p.parseStmt()
+               switch p.tok {
+               case token.IF:
+                       else_ = p.parseIfStmt()
+               case token.LBRACE:
+                       else_ = p.parseBlockStmt()
+                       p.expectSemi()
+               default:
+                       p.errorExpected(p.pos, "if statement or block")
+                       else_ = &ast.BadStmt{From: p.pos, To: p.pos}
+               }
        } else {
                p.expectSemi()
        }
@@ -1908,14 +1919,23 @@ func isTypeSwitchAssert(x ast.Expr) bool {
        return ok && a.Type == nil
 }
 
-func isTypeSwitchGuard(s ast.Stmt) bool {
+func (p *parser) isTypeSwitchGuard(s ast.Stmt) bool {
        switch t := s.(type) {
        case *ast.ExprStmt:
-               // x.(nil)
+               // x.(type)
                return isTypeSwitchAssert(t.X)
        case *ast.AssignStmt:
-               // v := x.(nil)
-               return len(t.Lhs) == 1 && t.Tok == token.DEFINE && len(t.Rhs) == 1 && isTypeSwitchAssert(t.Rhs[0])
+               // v := x.(type)
+               if len(t.Lhs) == 1 && len(t.Rhs) == 1 && isTypeSwitchAssert(t.Rhs[0]) {
+                       switch t.Tok {
+                       case token.ASSIGN:
+                               // permit v = x.(type) but complain
+                               p.error(t.TokPos, "expected ':=', found '='")
+                               fallthrough
+                       case token.DEFINE:
+                               return true
+                       }
+               }
        }
        return false
 }
@@ -1961,7 +1981,7 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
                p.exprLev = prevLev
        }
 
-       typeSwitch := isTypeSwitchGuard(s2)
+       typeSwitch := p.isTypeSwitchGuard(s2)
        lbrace := p.expect(token.LBRACE)
        var list []ast.Stmt
        for p.tok == token.CASE || p.tok == token.DEFAULT {
index ef2ffadbd981c09400d5bd4c2e92fcdbf4164b18..cdd343ea3c1fd6df8c67772c24eaba6e8544725c 100644 (file)
@@ -64,7 +64,7 @@ var invalids = []string{
        `package p; func f() { for _ = range x ; /* ERROR "expected '{'" */ ; {} };`,
        `package p; func f() { for ; ; _ = range /* ERROR "expected operand" */ x {} };`,
        `package p; func f() { for ; _ /* ERROR "expected boolean or range expression" */ = range x ; {} };`,
-       `package p; func f() { switch t /* ERROR "expected switch expression" */ = t.(type) {} };`,
+       `package p; func f() { switch t = /* ERROR "expected ':=', found '='" */ t.(type) {} };`,
        `package p; func f() { switch t /* ERROR "expected switch expression" */ , t = t.(type) {} };`,
        `package p; func f() { switch t /* ERROR "expected switch expression" */ = t.(type), t {} };`,
        `package p; var a = [ /* ERROR "expected expression" */ 1]int;`,
@@ -101,11 +101,30 @@ var invalids = []string{
        `package p; func f() { defer func() {} /* ERROR HERE "function must be invoked" */ }`,
        `package p; func f() { go func() { func() { f(x func /* ERROR "missing ','" */ (){}) } } }`,
        `package p; func f(x func(), u v func /* ERROR "missing ','" */ ()){}`,
-       `package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`,           // issue 8656
-       `package p; var x /* ERROR "missing variable type or initialization" */ , y, z;`, // issue 9639
-       `package p; const x /* ERROR "missing constant value" */ ;`,                      // issue 9639
-       `package p; const x /* ERROR "missing constant value" */ int;`,                   // issue 9639
-       `package p; const (x = 0; y; z /* ERROR "missing constant value" */ int);`,       // issue 9639
+
+       // issue 8656
+       `package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`,
+
+       // issue 9639
+       `package p; var x /* ERROR "missing variable type or initialization" */ , y, z;`,
+       `package p; const x /* ERROR "missing constant value" */ ;`,
+       `package p; const x /* ERROR "missing constant value" */ int;`,
+       `package p; const (x = 0; y; z /* ERROR "missing constant value" */ int);`,
+
+       // issue 12437
+       `package p; var _ = struct { x int, /* ERROR "expected ';', found ','" */ }{};`,
+       `package p; var _ = struct { x int, /* ERROR "expected ';', found ','" */ y float }{};`,
+
+       // issue 11611
+       `package p; type _ struct { int, } /* ERROR "expected type, found '}'" */ ;`,
+       `package p; type _ struct { int, float } /* ERROR "expected type, found '}'" */ ;`,
+       `package p; type _ struct { ( /* ERROR "expected anonymous field" */ int) };`,
+       `package p; func _()(x, y, z ... /* ERROR "expected '\)', found '...'" */ int){}`,
+       `package p; func _()(... /* ERROR "expected type, found '...'" */ int){}`,
+
+       // issue 13475
+       `package p; func f() { if true {} else ; /* ERROR "expected if statement or block" */ }`,
+       `package p; func f() { if true {} else defer /* ERROR "expected if statement or block" */ f() }`,
 }
 
 func TestInvalid(t *testing.T) {
index fe047053afb01a934e66eb710051f7acea2b2876..11f26d45ea39429afb6eed2f4ee03588812dbaf5 100644 (file)
@@ -747,13 +747,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
                }
 
        case *ast.SelectorExpr:
-               p.expr1(x.X, token.HighestPrec, depth)
-               p.print(token.PERIOD)
-               if line := p.lineFor(x.Sel.Pos()); p.pos.IsValid() && p.pos.Line < line {
-                       p.print(indent, newline, x.Sel.Pos(), x.Sel, unindent)
-               } else {
-                       p.print(x.Sel.Pos(), x.Sel)
-               }
+               p.selectorExpr(x, depth, false)
 
        case *ast.TypeAssertExpr:
                p.expr1(x.X, token.HighestPrec, depth)
@@ -802,13 +796,14 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
                if len(x.Args) > 1 {
                        depth++
                }
+               var wasIndented bool
                if _, ok := x.Fun.(*ast.FuncType); ok {
                        // conversions to literal function types require parentheses around the type
                        p.print(token.LPAREN)
-                       p.expr1(x.Fun, token.HighestPrec, depth)
+                       wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
                        p.print(token.RPAREN)
                } else {
-                       p.expr1(x.Fun, token.HighestPrec, depth)
+                       wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
                }
                p.print(x.Lparen, token.LPAREN)
                if x.Ellipsis.IsValid() {
@@ -821,6 +816,9 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
                        p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen)
                }
                p.print(x.Rparen, token.RPAREN)
+               if wasIndented {
+                       p.print(unindent)
+               }
 
        case *ast.CompositeLit:
                // composite literal elements that are composite literals themselves may have the type omitted
@@ -891,6 +889,30 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
        return
 }
 
+func (p *printer) possibleSelectorExpr(expr ast.Expr, prec1, depth int) bool {
+       if x, ok := expr.(*ast.SelectorExpr); ok {
+               return p.selectorExpr(x, depth, true)
+       }
+       p.expr1(expr, prec1, depth)
+       return false
+}
+
+// selectorExpr handles an *ast.SelectorExpr node and returns whether x spans
+// multiple lines.
+func (p *printer) selectorExpr(x *ast.SelectorExpr, depth int, isMethod bool) bool {
+       p.expr1(x.X, token.HighestPrec, depth)
+       p.print(token.PERIOD)
+       if line := p.lineFor(x.Sel.Pos()); p.pos.IsValid() && p.pos.Line < line {
+               p.print(indent, newline, x.Sel.Pos(), x.Sel)
+               if !isMethod {
+                       p.print(unindent)
+               }
+               return true
+       }
+       p.print(x.Sel.Pos(), x.Sel)
+       return false
+}
+
 func (p *printer) expr0(x ast.Expr, depth int) {
        p.expr1(x, token.LowestPrec, depth)
 }
@@ -1163,6 +1185,9 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) {
                        case *ast.BlockStmt, *ast.IfStmt:
                                p.stmt(s.Else, nextIsRBrace)
                        default:
+                               // This can only happen with an incorrectly
+                               // constructed AST. Permit it but print so
+                               // that it can be parsed without errors.
                                p.print(token.LBRACE, indent, formfeed)
                                p.stmt(s.Else, true)
                                p.print(unindent, formfeed, token.RBRACE)
index f9343d3af0d740942e77915ac64228a6b4b243f5..a3eaa6638e30e7e18725a25fe24af1d5b4d0ccc8 100644 (file)
@@ -1178,7 +1178,9 @@ func (p *trimmer) Write(data []byte) (n int, err error) {
                        case '\n', '\f':
                                _, err = p.output.Write(data[m:n])
                                p.resetSpace()
-                               _, err = p.output.Write(aNewline)
+                               if err == nil {
+                                       _, err = p.output.Write(aNewline)
+                               }
                        case tabwriter.Escape:
                                _, err = p.output.Write(data[m:n])
                                p.state = inEscape
index 3b0570e5b502a76f4301bf0985e5a35ae7cb61c3..73f9ead5a3e7beaf454bdd473c2a976b1759e421 100644 (file)
@@ -12,6 +12,7 @@ import (
        "go/ast"
        "go/parser"
        "go/token"
+       "io"
        "io/ioutil"
        "path/filepath"
        "testing"
@@ -548,6 +549,46 @@ func f()
        }
 }
 
+type limitWriter struct {
+       remaining int
+       errCount  int
+}
+
+func (l *limitWriter) Write(buf []byte) (n int, err error) {
+       n = len(buf)
+       if n >= l.remaining {
+               n = l.remaining
+               err = io.EOF
+               l.errCount++
+       }
+       l.remaining -= n
+       return n, err
+}
+
+// Test whether the printer stops writing after the first error
+func TestWriteErrors(t *testing.T) {
+       const filename = "printer.go"
+       src, err := ioutil.ReadFile(filename)
+       if err != nil {
+               panic(err) // error in test
+       }
+       file, err := parser.ParseFile(fset, filename, src, 0)
+       if err != nil {
+               panic(err) // error in test
+       }
+       for i := 0; i < 20; i++ {
+               lw := &limitWriter{remaining: i}
+               err := (&Config{Mode: RawFormat}).Fprint(lw, fset, file)
+               if lw.errCount > 1 {
+                       t.Fatal("Writes continued after first error returned")
+               }
+               // We expect errCount be 1 iff err is set
+               if (lw.errCount != 0) != (err != nil) {
+                       t.Fatal("Expected err when errCount != 0")
+               }
+       }
+}
+
 // TextX is a skeleton test that can be filled in for debugging one-off cases.
 // Do not remove.
 func TestX(t *testing.T) {
index e3d17a4653f4bc20f567ba78d022512ab197dbb4..cab991fd883dfdc2d78179fe2eebb1d5be79b375 100644 (file)
@@ -567,7 +567,7 @@ func _() {
        // handle multiline argument list correctly
        _ = new(T).
                foo(
-               1).
+                       1).
                foo(2)
 
        _ = new(T).foo(
@@ -614,7 +614,7 @@ func _() {
                Blob.(*Type).
                Slices[1:4].
                Method(1, 2,
-               3).
+                       3).
                Thingy
 
        _ = a.b.c
@@ -684,3 +684,21 @@ func _() {
        _ = (func(x int) float)(nil)
        _ = (func() func() func())(nil)
 }
+
+func _() {
+       _ = f().
+               f(func() {
+                       f()
+               }).
+               f(map[int]int{
+                       1:      2,
+                       3:      4,
+               })
+
+       _ = f().
+               f(
+                       func() {
+                               f()
+                       },
+               )
+}
index d20a59350ed6db32f125ef9df9d93eeb6d28993d..7c88042dc1754b9edd9ff06be70fd2d2d1747b63 100644 (file)
@@ -713,3 +713,21 @@ func _() {
        _ = (func(x int)(float))(nil)
        _ = (func() func() func()())(nil)
 }
+
+func _() {
+       _ = f().
+       f(func() {
+               f()
+       }).
+       f(map[int]int{
+       1: 2,
+       3: 4,
+})
+
+       _ = f().
+       f(
+       func() {
+               f()
+       },
+       )
+}
index 2357336957fe0c04905acdc1285d02b1dc192fbd..d9060621ced5f55cb78c650924aca71344e301b6 100644 (file)
@@ -567,7 +567,7 @@ func _() {
        // handle multiline argument list correctly
        _ = new(T).
                foo(
-               1).
+                       1).
                foo(2)
 
        _ = new(T).foo(
@@ -614,7 +614,7 @@ func _() {
                Blob.(*Type).
                Slices[1:4].
                Method(1, 2,
-               3).
+                       3).
                Thingy
 
        _ = a.b.c
@@ -684,3 +684,21 @@ func _() {
        _ = (func(x int) float)(nil)
        _ = (func() func() func())(nil)
 }
+
+func _() {
+       _ = f().
+               f(func() {
+                       f()
+               }).
+               f(map[int]int{
+                       1:      2,
+                       3:      4,
+               })
+
+       _ = f().
+               f(
+                       func() {
+                               f()
+                       },
+               )
+}
index b3bf6f01476dbf25d533dfb8993e915d7529f679..ca109f0a80fdb735ec72affb74d38bcc9e3bf558 100644 (file)
@@ -22,6 +22,8 @@
 // and checks for compliance with the language specification.
 // Use Info.Types[expr].Type for the results of type inference.
 //
+// For a tutorial, see https://golang.org/s/types-tutorial.
+//
 package types // import "go/types"
 
 import (
@@ -49,16 +51,42 @@ func (err Error) Error() string {
        return fmt.Sprintf("%s: %s", err.Fset.Position(err.Pos), err.Msg)
 }
 
-// An importer resolves import paths to Packages.
-// See go/importer for existing implementations.
+// An Importer resolves import paths to Packages.
+//
+// CAUTION: This interface does not support the import of locally
+// vendored packages. See https://golang.org/s/go15vendor.
+// If possible, external implementations should implement ImporterFrom.
 type Importer interface {
        // Import returns the imported package for the given import
        // path, or an error if the package couldn't be imported.
-       // Import is responsible for returning the same package for
-       // matching import paths.
+       // Two calls to Import with the same path return the same
+       // package.
        Import(path string) (*Package, error)
 }
 
+// ImportMode is reserved for future use.
+type ImportMode int
+
+// An ImporterFrom resolves import paths to packages; it
+// supports vendoring per https://golang.org/s/go15vendor.
+// Use go/importer to obtain an ImporterFrom implementation.
+type ImporterFrom interface {
+       // Importer is present for backward-compatibility. Calling
+       // Import(path) is the same as calling ImportFrom(path, "", 0);
+       // i.e., locally vendored packages may not be found.
+       // The types package does not call Import if an ImporterFrom
+       // is present.
+       Importer
+
+       // ImportFrom returns the imported package for the given import
+       // path when imported by the package in srcDir, or an error
+       // if the package couldn't be imported. The mode value must
+       // be 0; it is reserved for future use.
+       // Two calls to ImportFrom with the same path and srcDir return
+       // the same package.
+       ImportFrom(path, srcDir string, mode ImportMode) (*Package, error)
+}
+
 // A Config specifies the configuration for type checking.
 // The zero value for Config is a ready-to-use default configuration.
 type Config struct {
@@ -84,9 +112,12 @@ type Config struct {
        // error found.
        Error func(err error)
 
-       // Importer is called for each import declaration except when
-       // importing package "unsafe". An error is reported if an
-       // importer is needed but none was installed.
+       // An importer is used to import packages referred to from
+       // import declarations.
+       // If the installed importer implements ImporterFrom, the type
+       // checker calls ImportFrom instead of Import.
+       // The type checker reports an error if an importer is needed
+       // but none was installed.
        Importer Importer
 
        // If Sizes != nil, it provides the sizing functions for package unsafe.
@@ -142,7 +173,7 @@ type Info struct {
        //
        //      *ast.ImportSpec    *PkgName for dot-imports and imports without renames
        //      *ast.CaseClause    type-specific *Var for each type switch case clause (incl. default)
-       //      *ast.Field         anonymous struct field or parameter *Var
+       //      *ast.Field         anonymous parameter *Var
        //
        Implicits map[ast.Node]Object
 
@@ -297,8 +328,10 @@ func (init *Initializer) String() string {
        return buf.String()
 }
 
-// Check type-checks a package and returns the resulting package object,
-// the first error if any, and if info != nil, additional type information.
+// Check type-checks a package and returns the resulting package object and
+// the first error if any. Additionally, if info != nil, Check populates each
+// of the non-nil maps in the Info struct.
+//
 // The package is marked as complete if no errors occurred, otherwise it is
 // incomplete. See Config.Error for controlling behavior in the presence of
 // errors.
@@ -320,7 +353,7 @@ func AssertableTo(V *Interface, T Type) bool {
 // AssignableTo reports whether a value of type V is assignable to a variable of type T.
 func AssignableTo(V, T Type) bool {
        x := operand{mode: value, typ: V}
-       return x.assignableTo(nil, T) // config not needed for non-constant x
+       return x.assignableTo(nil, T, nil) // config not needed for non-constant x
 }
 
 // ConvertibleTo reports whether a value of type V is convertible to a value of type T.
index eeda0d847c371ea55e83ba74abea936f2bf1a6a4..97af965c9f67045f156f17d9a7d8fb0d61e04af0 100644 (file)
@@ -32,6 +32,7 @@ func pkgFor(path, source string, info *Info) (*Package, error) {
 }
 
 func mustTypecheck(t *testing.T, path, source string, info *Info) string {
+       t.Skip("skipping for gccgo--no importer")
        pkg, err := pkgFor(path, source, info)
        if err != nil {
                name := path
@@ -54,14 +55,14 @@ func TestValuesInfo(t *testing.T) {
                {`package a1; const _ = 0`, `0`, `untyped int`, `0`},
                {`package a2; const _ = 'A'`, `'A'`, `untyped rune`, `65`},
                {`package a3; const _ = 0.`, `0.`, `untyped float`, `0`},
-               {`package a4; const _ = 0i`, `0i`, `untyped complex`, `0`},
+               {`package a4; const _ = 0i`, `0i`, `untyped complex`, `(0 + 0i)`},
                {`package a5; const _ = "foo"`, `"foo"`, `untyped string`, `"foo"`},
 
                {`package b0; var _ = false`, `false`, `bool`, `false`},
                {`package b1; var _ = 0`, `0`, `int`, `0`},
                {`package b2; var _ = 'A'`, `'A'`, `rune`, `65`},
                {`package b3; var _ = 0.`, `0.`, `float64`, `0`},
-               {`package b4; var _ = 0i`, `0i`, `complex128`, `0`},
+               {`package b4; var _ = 0i`, `0i`, `complex128`, `(0 + 0i)`},
                {`package b5; var _ = "foo"`, `"foo"`, `string`, `"foo"`},
 
                {`package c0a; var _ = bool(false)`, `false`, `bool`, `false`},
@@ -80,9 +81,9 @@ func TestValuesInfo(t *testing.T) {
                {`package c3b; var _ = float32(0.)`, `float32(0.)`, `float32`, `0`},
                {`package c3c; type T float32; var _ = T(0.)`, `T(0.)`, `c3c.T`, `0`},
 
-               {`package c4a; var _ = complex64(0i)`, `0i`, `complex64`, `0`},
-               {`package c4b; var _ = complex64(0i)`, `complex64(0i)`, `complex64`, `0`},
-               {`package c4c; type T complex64; var _ = T(0i)`, `T(0i)`, `c4c.T`, `0`},
+               {`package c4a; var _ = complex64(0i)`, `0i`, `complex64`, `(0 + 0i)`},
+               {`package c4b; var _ = complex64(0i)`, `complex64(0i)`, `complex64`, `(0 + 0i)`},
+               {`package c4c; type T complex64; var _ = T(0i)`, `T(0i)`, `c4c.T`, `(0 + 0i)`},
 
                {`package c5a; var _ = string("foo")`, `"foo"`, `string`, `"foo"`},
                {`package c5b; var _ = string("foo")`, `string("foo")`, `string`, `"foo"`},
@@ -97,10 +98,10 @@ func TestValuesInfo(t *testing.T) {
                {`package e1; const _ = float32(-1e-200)`, `float32(-1e-200)`, `float32`, `0`},
                {`package e2; const _ = float64( 1e-2000)`, `float64(1e-2000)`, `float64`, `0`},
                {`package e3; const _ = float64(-1e-2000)`, `float64(-1e-2000)`, `float64`, `0`},
-               {`package e4; const _ = complex64( 1e-200)`, `complex64(1e-200)`, `complex64`, `0`},
-               {`package e5; const _ = complex64(-1e-200)`, `complex64(-1e-200)`, `complex64`, `0`},
-               {`package e6; const _ = complex128( 1e-2000)`, `complex128(1e-2000)`, `complex128`, `0`},
-               {`package e7; const _ = complex128(-1e-2000)`, `complex128(-1e-2000)`, `complex128`, `0`},
+               {`package e4; const _ = complex64( 1e-200)`, `complex64(1e-200)`, `complex64`, `(0 + 0i)`},
+               {`package e5; const _ = complex64(-1e-200)`, `complex64(-1e-200)`, `complex64`, `(0 + 0i)`},
+               {`package e6; const _ = complex128( 1e-2000)`, `complex128(1e-2000)`, `complex128`, `(0 + 0i)`},
+               {`package e7; const _ = complex128(-1e-2000)`, `complex128(-1e-2000)`, `complex128`, `(0 + 0i)`},
 
                {`package f0 ; var _ float32 =  1e-200`, `1e-200`, `float32`, `0`},
                {`package f1 ; var _ float32 = -1e-200`, `-1e-200`, `float32`, `0`},
@@ -108,12 +109,12 @@ func TestValuesInfo(t *testing.T) {
                {`package f3a; var _ float64 = -1e-2000`, `-1e-2000`, `float64`, `0`},
                {`package f2b; var _         =  1e-2000`, `1e-2000`, `float64`, `0`},
                {`package f3b; var _         = -1e-2000`, `-1e-2000`, `float64`, `0`},
-               {`package f4 ; var _ complex64  =  1e-200 `, `1e-200`, `complex64`, `0`},
-               {`package f5 ; var _ complex64  = -1e-200 `, `-1e-200`, `complex64`, `0`},
-               {`package f6a; var _ complex128 =  1e-2000i`, `1e-2000i`, `complex128`, `0`},
-               {`package f7a; var _ complex128 = -1e-2000i`, `-1e-2000i`, `complex128`, `0`},
-               {`package f6b; var _            =  1e-2000i`, `1e-2000i`, `complex128`, `0`},
-               {`package f7b; var _            = -1e-2000i`, `-1e-2000i`, `complex128`, `0`},
+               {`package f4 ; var _ complex64  =  1e-200 `, `1e-200`, `complex64`, `(0 + 0i)`},
+               {`package f5 ; var _ complex64  = -1e-200 `, `-1e-200`, `complex64`, `(0 + 0i)`},
+               {`package f6a; var _ complex128 =  1e-2000i`, `1e-2000i`, `complex128`, `(0 + 0i)`},
+               {`package f7a; var _ complex128 = -1e-2000i`, `-1e-2000i`, `complex128`, `(0 + 0i)`},
+               {`package f6b; var _            =  1e-2000i`, `1e-2000i`, `complex128`, `(0 + 0i)`},
+               {`package f7b; var _            = -1e-2000i`, `-1e-2000i`, `complex128`, `(0 + 0i)`},
        }
 
        for _, test := range tests {
@@ -143,7 +144,7 @@ func TestValuesInfo(t *testing.T) {
                }
 
                // check that value is correct
-               if got := tv.Value.String(); got != test.val {
+               if got := tv.Value.ExactString(); got != test.val {
                        t.Errorf("package %s: got value %s; want %s", name, got, test.val)
                }
        }
@@ -797,7 +798,7 @@ func main() {
        makePkg("main", mainSrc)
 
        for e, sel := range selections {
-               sel.String() // assertion: must not panic
+               _ = sel.String() // assertion: must not panic
 
                start := fset.Position(e.Pos()).Offset
                end := fset.Position(e.End()).Offset
@@ -872,6 +873,7 @@ var _ = a.C2
 }
 
 func TestLookupFieldOrMethod(t *testing.T) {
+       t.Skip("skipping for gccgo--no importer")
        // Test cases assume a lookup of the form a.f or x.f, where a stands for an
        // addressable value, and x for a non-addressable value (even though a variable
        // for ease of test case writing).
index e88de56a0daf79c94b49207bf10dad5ef77dfe3d..10ab17b9cf9ab4753db70556ff9e5747cf2748eb 100644 (file)
@@ -13,31 +13,21 @@ import (
 
 // assignment reports whether x can be assigned to a variable of type T,
 // if necessary by attempting to convert untyped values to the appropriate
-// type. If x.mode == invalid upon return, then assignment has already
-// issued an error message and the caller doesn't have to report another.
+// type. context describes the context in which the assignment takes place.
 // Use T == nil to indicate assignment to an untyped blank identifier.
-//
-// TODO(gri) Should find a better way to handle in-band errors.
-//
-func (check *Checker) assignment(x *operand, T Type) bool {
+// x.mode is set to invalid if the assignment failed.
+func (check *Checker) assignment(x *operand, T Type, context string) {
+       check.singleValue(x)
+
        switch x.mode {
        case invalid:
-               return true // error reported before
+               return // error reported before
        case constant_, variable, mapindex, value, commaok:
                // ok
        default:
                unreachable()
        }
 
-       // x must be a single value
-       // (tuple types are never named - no need for underlying type)
-       if t, _ := x.typ.(*Tuple); t != nil {
-               assert(t.Len() > 1)
-               check.errorf(x.pos(), "%d-valued expression %s used as single value", t.Len(), x)
-               x.mode = invalid
-               return false
-       }
-
        if isUntyped(x.typ) {
                target := T
                // spec: "If an untyped constant is assigned to a variable of interface
@@ -47,22 +37,34 @@ func (check *Checker) assignment(x *operand, T Type) bool {
                // or string constant."
                if T == nil || IsInterface(T) {
                        if T == nil && x.typ == Typ[UntypedNil] {
-                               check.errorf(x.pos(), "use of untyped nil")
+                               check.errorf(x.pos(), "use of untyped nil in %s", context)
                                x.mode = invalid
-                               return false
+                               return
                        }
                        target = defaultType(x.typ)
                }
                check.convertUntyped(x, target)
                if x.mode == invalid {
-                       return false
+                       return
                }
        }
+       // x.typ is typed
 
        // spec: "If a left-hand side is the blank identifier, any typed or
        // non-constant value except for the predeclared identifier nil may
        // be assigned to it."
-       return T == nil || x.assignableTo(check.conf, T)
+       if T == nil {
+               return
+       }
+
+       if reason := ""; !x.assignableTo(check.conf, T, &reason) {
+               if reason != "" {
+                       check.errorf(x.pos(), "cannot use %s as %s value in %s: %s", x, T, context, reason)
+               } else {
+                       check.errorf(x.pos(), "cannot use %s as %s value in %s", x, T, context)
+               }
+               x.mode = invalid
+       }
 }
 
 func (check *Checker) initConst(lhs *Const, x *operand) {
@@ -88,18 +90,15 @@ func (check *Checker) initConst(lhs *Const, x *operand) {
                lhs.typ = x.typ
        }
 
-       if !check.assignment(x, lhs.typ) {
-               if x.mode != invalid {
-                       check.errorf(x.pos(), "cannot define constant %s (type %s) as %s", lhs.Name(), lhs.typ, x)
-               }
+       check.assignment(x, lhs.typ, "constant declaration")
+       if x.mode == invalid {
                return
        }
 
        lhs.val = x.val
 }
 
-// If result is set, lhs is a function result parameter and x is a return result.
-func (check *Checker) initVar(lhs *Var, x *operand, result bool) Type {
+func (check *Checker) initVar(lhs *Var, x *operand, context string) Type {
        if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
                if lhs.typ == nil {
                        lhs.typ = Typ[Invalid]
@@ -113,7 +112,7 @@ func (check *Checker) initVar(lhs *Var, x *operand, result bool) Type {
                if isUntyped(typ) {
                        // convert untyped types to default types
                        if typ == Typ[UntypedNil] {
-                               check.errorf(x.pos(), "use of untyped nil")
+                               check.errorf(x.pos(), "use of untyped nil in %s", context)
                                lhs.typ = Typ[Invalid]
                                return nil
                        }
@@ -122,15 +121,8 @@ func (check *Checker) initVar(lhs *Var, x *operand, result bool) Type {
                lhs.typ = typ
        }
 
-       if !check.assignment(x, lhs.typ) {
-               if x.mode != invalid {
-                       if result {
-                               // don't refer to lhs.name because it may be an anonymous result parameter
-                               check.errorf(x.pos(), "cannot return %s as value of type %s", x, lhs.typ)
-                       } else {
-                               check.errorf(x.pos(), "cannot initialize %s with %s", lhs, x)
-                       }
-               }
+       check.assignment(x, lhs.typ, context)
+       if x.mode == invalid {
                return nil
        }
 
@@ -148,9 +140,9 @@ func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
        // Don't evaluate lhs if it is the blank identifier.
        if ident != nil && ident.Name == "_" {
                check.recordDef(ident, nil)
-               if !check.assignment(x, nil) {
-                       assert(x.mode == invalid)
-                       x.typ = nil
+               check.assignment(x, nil, "assignment to _ identifier")
+               if x.mode == invalid {
+                       return nil
                }
                return x.typ
        }
@@ -191,10 +183,8 @@ func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
                return nil
        }
 
-       if !check.assignment(x, z.typ) {
-               if x.mode != invalid {
-                       check.errorf(x.pos(), "cannot assign %s to %s", x, &z)
-               }
+       check.assignment(x, z.typ, "assignment")
+       if x.mode == invalid {
                return nil
        }
 
@@ -205,7 +195,7 @@ func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
 // return expressions, and returnPos is the position of the return statement.
 func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos) {
        l := len(lhs)
-       get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
+       get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
        if get == nil || l != r {
                // invalidate lhs and use rhs
                for _, obj := range lhs {
@@ -225,12 +215,17 @@ func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos)
                return
        }
 
+       context := "assignment"
+       if returnPos.IsValid() {
+               context = "return statement"
+       }
+
        var x operand
        if commaOk {
                var a [2]Type
                for i := range a {
                        get(&x, i)
-                       a[i] = check.initVar(lhs[i], &x, returnPos.IsValid())
+                       a[i] = check.initVar(lhs[i], &x, context)
                }
                check.recordCommaOkTypes(rhs[0], a)
                return
@@ -238,13 +233,13 @@ func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos)
 
        for i, lhs := range lhs {
                get(&x, i)
-               check.initVar(lhs, &x, returnPos.IsValid())
+               check.initVar(lhs, &x, context)
        }
 }
 
 func (check *Checker) assignVars(lhs, rhs []ast.Expr) {
        l := len(lhs)
-       get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2)
+       get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2)
        if get == nil {
                return // error reported by unpack
        }
index 47295914d00e5ecac11bb241764fa97d512e3fc8..803264fb585de442fd1f843b41aa6b78d88ada62 100644 (file)
@@ -44,7 +44,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
        switch id {
        default:
                // make argument getter
-               arg, nargs, _ = unpack(func(x *operand, i int) { check.expr(x, call.Args[i]) }, nargs, false)
+               arg, nargs, _ = unpack(func(x *operand, i int) { check.multiExpr(x, call.Args[i]) }, nargs, false)
                if arg == nil {
                        return
                }
@@ -95,7 +95,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                // spec: "As a special case, append also accepts a first argument assignable
                // to type []byte with a second argument of string type followed by ... .
                // This form appends the bytes of the string.
-               if nargs == 2 && call.Ellipsis.IsValid() && x.assignableTo(check.conf, NewSlice(universeByte)) {
+               if nargs == 2 && call.Ellipsis.IsValid() && x.assignableTo(check.conf, NewSlice(universeByte), nil) {
                        arg(x, 1)
                        if x.mode == invalid {
                                return
@@ -200,77 +200,96 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                }
 
        case _Complex:
-               // complex(x, y realT) complexT
-               if !check.complexArg(x) {
-                       return
-               }
-
+               // complex(x, y floatT) complexT
                var y operand
                arg(&y, 1)
                if y.mode == invalid {
                        return
                }
-               if !check.complexArg(&y) {
-                       return
-               }
 
-               check.convertUntyped(x, y.typ)
-               if x.mode == invalid {
-                       return
+               // convert or check untyped arguments
+               d := 0
+               if isUntyped(x.typ) {
+                       d |= 1
+               }
+               if isUntyped(y.typ) {
+                       d |= 2
+               }
+               switch d {
+               case 0:
+                       // x and y are typed => nothing to do
+               case 1:
+                       // only x is untyped => convert to type of y
+                       check.convertUntyped(x, y.typ)
+               case 2:
+                       // only y is untyped => convert to type of x
+                       check.convertUntyped(&y, x.typ)
+               case 3:
+                       // x and y are untyped =>
+                       // 1) if both are constants, convert them to untyped
+                       //    floating-point numbers if possible,
+                       // 2) if one of them is not constant (possible because
+                       //    it contains a shift that is yet untyped), convert
+                       //    both of them to float64 since they must have the
+                       //    same type to succeed (this will result in an error
+                       //    because shifts of floats are not permitted)
+                       if x.mode == constant_ && y.mode == constant_ {
+                               toFloat := func(x *operand) {
+                                       if isNumeric(x.typ) && constant.Sign(constant.Imag(x.val)) == 0 {
+                                               x.typ = Typ[UntypedFloat]
+                                       }
+                               }
+                               toFloat(x)
+                               toFloat(&y)
+                       } else {
+                               check.convertUntyped(x, Typ[Float64])
+                               check.convertUntyped(&y, Typ[Float64])
+                               // x and y should be invalid now, but be conservative
+                               // and check below
+                       }
                }
-               check.convertUntyped(&y, x.typ)
-               if y.mode == invalid {
+               if x.mode == invalid || y.mode == invalid {
                        return
                }
 
+               // both argument types must be identical
                if !Identical(x.typ, y.typ) {
                        check.invalidArg(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
                        return
                }
 
+               // the argument types must be of floating-point type
+               if !isFloat(x.typ) {
+                       check.invalidArg(x.pos(), "arguments have type %s, expected floating-point", x.typ)
+                       return
+               }
+
+               // if both arguments are constants, the result is a constant
                if x.mode == constant_ && y.mode == constant_ {
-                       x.val = constant.BinaryOp(x.val, token.ADD, constant.MakeImag(y.val))
+                       x.val = constant.BinaryOp(constant.ToFloat(x.val), token.ADD, constant.MakeImag(constant.ToFloat(y.val)))
                } else {
                        x.mode = value
                }
 
-               realT := x.typ
-               complexT := Typ[Invalid]
-               switch realT.Underlying().(*Basic).kind {
+               // determine result type
+               var res BasicKind
+               switch x.typ.Underlying().(*Basic).kind {
                case Float32:
-                       complexT = Typ[Complex64]
+                       res = Complex64
                case Float64:
-                       complexT = Typ[Complex128]
-               case UntypedInt, UntypedRune, UntypedFloat:
-                       if x.mode == constant_ {
-                               realT = defaultType(realT).(*Basic)
-                               complexT = Typ[UntypedComplex]
-                       } else {
-                               // untyped but not constant; probably because one
-                               // operand is a non-constant shift of untyped lhs
-                               realT = Typ[Float64]
-                               complexT = Typ[Complex128]
-                       }
+                       res = Complex128
+               case UntypedFloat:
+                       res = UntypedComplex
                default:
-                       check.invalidArg(x.pos(), "float32 or float64 arguments expected")
-                       return
+                       unreachable()
                }
+               resTyp := Typ[res]
 
-               x.typ = complexT
                if check.Types != nil && x.mode != constant_ {
-                       check.recordBuiltinType(call.Fun, makeSig(complexT, realT, realT))
+                       check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ, x.typ))
                }
 
-               if x.mode != constant_ {
-                       // The arguments have now their final types, which at run-
-                       // time will be materialized. Update the expression trees.
-                       // If the current types are untyped, the materialized type
-                       // is the respective default type.
-                       // (If the result is constant, the arguments are never
-                       // materialized and there is nothing to do.)
-                       check.updateExprType(x.expr, realT, true)
-                       check.updateExprType(y.expr, realT, true)
-               }
+               x.typ = resTyp
 
        case _Copy:
                // copy(x, y []T) int
@@ -322,7 +341,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                        return
                }
 
-               if !x.assignableTo(check.conf, m.key) {
+               if !x.assignableTo(check.conf, m.key, nil) {
                        check.invalidArg(x.pos(), "%s is not assignable to %s", x, m.key)
                        return
                }
@@ -333,12 +352,37 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                }
 
        case _Imag, _Real:
-               // imag(complexT) realT
-               // real(complexT) realT
+               // imag(complexT) floatT
+               // real(complexT) floatT
+
+               // convert or check untyped argument
+               if isUntyped(x.typ) {
+                       if x.mode == constant_ {
+                               // an untyped constant number can alway be considered
+                               // as a complex constant
+                               if isNumeric(x.typ) {
+                                       x.typ = Typ[UntypedComplex]
+                               }
+                       } else {
+                               // an untyped non-constant argument may appear if
+                               // it contains a (yet untyped non-constant) shift
+                               // epression: convert it to complex128 which will
+                               // result in an error (shift of complex value)
+                               check.convertUntyped(x, Typ[Complex128])
+                               // x should be invalid now, but be conservative and check
+                               if x.mode == invalid {
+                                       return
+                               }
+                       }
+               }
+
+               // the argument must be of complex type
                if !isComplex(x.typ) {
-                       check.invalidArg(x.pos(), "%s must be a complex number", x)
+                       check.invalidArg(x.pos(), "argument has type %s, expected complex type", x.typ)
                        return
                }
+
+               // if the argument is a constant, the result is a constant
                if x.mode == constant_ {
                        if id == _Real {
                                x.val = constant.Real(x.val)
@@ -348,22 +392,26 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                } else {
                        x.mode = value
                }
-               var k BasicKind
+
+               // determine result type
+               var res BasicKind
                switch x.typ.Underlying().(*Basic).kind {
                case Complex64:
-                       k = Float32
+                       res = Float32
                case Complex128:
-                       k = Float64
+                       res = Float64
                case UntypedComplex:
-                       k = UntypedFloat
+                       res = UntypedFloat
                default:
                        unreachable()
                }
+               resTyp := Typ[res]
 
                if check.Types != nil && x.mode != constant_ {
-                       check.recordBuiltinType(call.Fun, makeSig(Typ[k], x.typ))
+                       check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ))
                }
-               x.typ = Typ[k]
+
+               x.typ = resTyp
 
        case _Make:
                // make(T, n)
@@ -423,8 +471,8 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
        case _Panic:
                // panic(x)
                T := new(Interface)
-               if !check.assignment(x, T) {
-                       assert(x.mode == invalid)
+               check.assignment(x, T, "argument to panic")
+               if x.mode == invalid {
                        return
                }
 
@@ -443,8 +491,9 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                                if i > 0 {
                                        arg(x, i) // first argument already evaluated
                                }
-                               if !check.assignment(x, nil) {
-                                       assert(x.mode == invalid)
+                               check.assignment(x, nil, "argument to "+predeclaredFuncs[id].name)
+                               if x.mode == invalid {
+                                       // TODO(gri) "use" all arguments?
                                        return
                                }
                                params[i] = x.typ
@@ -466,8 +515,8 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
 
        case _Alignof:
                // unsafe.Alignof(x T) uintptr
-               if !check.assignment(x, nil) {
-                       assert(x.mode == invalid)
+               check.assignment(x, nil, "argument to unsafe.Alignof")
+               if x.mode == invalid {
                        return
                }
 
@@ -523,8 +572,8 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
 
        case _Sizeof:
                // unsafe.Sizeof(x T) uintptr
-               if !check.assignment(x, nil) {
-                       assert(x.mode == invalid)
+               check.assignment(x, nil, "argument to unsafe.Sizeof")
+               if x.mode == invalid {
                        return
                }
 
@@ -616,12 +665,3 @@ func unparen(e ast.Expr) ast.Expr {
                e = p.X
        }
 }
-
-func (check *Checker) complexArg(x *operand) bool {
-       t, _ := x.typ.Underlying().(*Basic)
-       if t != nil && (t.info&IsFloat != 0 || t.kind == UntypedInt || t.kind == UntypedRune) {
-               return true
-       }
-       check.invalidArg(x.pos(), "%s must be a float32, float64, or an untyped non-complex numeric constant", x)
-       return false
-}
index 9835a48267061054d0697ce2855cfe312e6b776a..67c49732bf5622c115080c32a226c60d6ba3acfb 100644 (file)
@@ -126,6 +126,8 @@ func TestBuiltinSignatures(t *testing.T) {
 }
 
 func testBuiltinSignature(t *testing.T, name, src0, want string) {
+       t.Skip("skipping for gccgo--no default importer")
+
        src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _() { %s }`, src0)
        f, err := parser.ParseFile(fset, "", src, 0)
        if err != nil {
index 62cefc047ef4f93ae76f3e48d0d85a05e167da34..8aeb862993f8520f590a158d7ac8cde53105e04a 100644 (file)
@@ -61,7 +61,7 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
                        return statement
                }
 
-               arg, n, _ := unpack(func(x *operand, i int) { check.expr(x, e.Args[i]) }, len(e.Args), false)
+               arg, n, _ := unpack(func(x *operand, i int) { check.multiExpr(x, e.Args[i]) }, len(e.Args), false)
                if arg == nil {
                        x.mode = invalid
                        x.expr = e
@@ -181,14 +181,14 @@ func unpack(get getter, n int, allowCommaOk bool) (getter, int, bool) {
 func (check *Checker) arguments(x *operand, call *ast.CallExpr, sig *Signature, arg getter, n int) {
        if call.Ellipsis.IsValid() {
                // last argument is of the form x...
-               if len(call.Args) == 1 && n > 1 {
-                       // f()... is not permitted if f() is multi-valued
-                       check.errorf(call.Ellipsis, "cannot use ... with %d-valued expression %s", n, call.Args[0])
+               if !sig.variadic {
+                       check.errorf(call.Ellipsis, "cannot use ... in call to non-variadic %s", call.Fun)
                        check.useGetter(arg, n)
                        return
                }
-               if !sig.variadic {
-                       check.errorf(call.Ellipsis, "cannot use ... in call to non-variadic %s", call.Fun)
+               if len(call.Args) == 1 && n > 1 {
+                       // f()... is not permitted if f() is multi-valued
+                       check.errorf(call.Ellipsis, "cannot use ... with %d-valued %s", n, call.Args[0])
                        check.useGetter(arg, n)
                        return
                }
@@ -202,7 +202,7 @@ func (check *Checker) arguments(x *operand, call *ast.CallExpr, sig *Signature,
                        if i == n-1 && call.Ellipsis.IsValid() {
                                ellipsis = call.Ellipsis
                        }
-                       check.argument(sig, i, x, ellipsis)
+                       check.argument(call.Fun, sig, i, x, ellipsis)
                }
        }
 
@@ -220,7 +220,12 @@ func (check *Checker) arguments(x *operand, call *ast.CallExpr, sig *Signature,
 
 // argument checks passing of argument x to the i'th parameter of the given signature.
 // If ellipsis is valid, the argument is followed by ... at that position in the call.
-func (check *Checker) argument(sig *Signature, i int, x *operand, ellipsis token.Pos) {
+func (check *Checker) argument(fun ast.Expr, sig *Signature, i int, x *operand, ellipsis token.Pos) {
+       check.singleValue(x)
+       if x.mode == invalid {
+               return
+       }
+
        n := sig.params.Len()
 
        // determine parameter type
@@ -241,18 +246,12 @@ func (check *Checker) argument(sig *Signature, i int, x *operand, ellipsis token
        }
 
        if ellipsis.IsValid() {
-               // argument is of the form x...
+               // argument is of the form x... and x is single-valued
                if i != n-1 {
                        check.errorf(ellipsis, "can only use ... with matching parameter")
                        return
                }
-               switch t := x.typ.Underlying().(type) {
-               case *Slice:
-                       // ok
-               case *Tuple:
-                       check.errorf(ellipsis, "cannot use ... with %d-valued expression %s", t.Len(), x)
-                       return
-               default:
+               if _, ok := x.typ.Underlying().(*Slice); !ok {
                        check.errorf(x.pos(), "cannot use %s as parameter of type %s", x, typ)
                        return
                }
@@ -261,9 +260,7 @@ func (check *Checker) argument(sig *Signature, i int, x *operand, ellipsis token
                typ = typ.(*Slice).elem
        }
 
-       if !check.assignment(x, typ) && x.mode != invalid {
-               check.errorf(x.pos(), "cannot pass argument %s to parameter of type %s", x, typ)
-       }
+       check.assignment(x, typ, check.sprintf("argument to %s", fun))
 }
 
 func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
index 5e34c65b6361926197d2aa52ef774deefc731e9a..5e2043be84b22ec33d0c0cf3ccd8af1f06b24737 100644 (file)
@@ -55,6 +55,7 @@ var tests = [][]string{
        {"testdata/errors.src"},
        {"testdata/importdecl0a.src", "testdata/importdecl0b.src"},
        {"testdata/importdecl1a.src", "testdata/importdecl1b.src"},
+       {"testdata/importC.src"}, // special handling in checkFiles
        {"testdata/cycles.src"},
        {"testdata/cycles1.src"},
        {"testdata/cycles2.src"},
@@ -245,6 +246,10 @@ func checkFiles(t *testing.T, testfiles []string) {
 
        // typecheck and collect typechecker errors
        var conf Config
+       // special case for importC.src
+       if len(testfiles) == 1 && testfiles[0] == "testdata/importC.src" {
+               conf.FakeImportC = true
+       }
        conf.Importer = importer.Default()
        conf.Error = func(err error) {
                if *listErrors {
index 74826ce93451f8a80b4132347971c02c471c3ccb..f98cc8d81a89f02f8fccdeb223bb50d9d6614052 100644 (file)
@@ -18,7 +18,7 @@ func (check *Checker) conversion(x *operand, T Type) {
        case constArg && isConstType(T):
                // constant conversion
                switch t := T.Underlying().(*Basic); {
-               case representableConst(x.val, check.conf, t.kind, &x.val):
+               case representableConst(x.val, check.conf, t, &x.val):
                        ok = true
                case isInteger(x.typ) && isString(t):
                        codepoint := int64(-1)
@@ -65,7 +65,7 @@ func (check *Checker) conversion(x *operand, T Type) {
 
 func (x *operand) convertibleTo(conf *Config, T Type) bool {
        // "x is assignable to T"
-       if x.assignableTo(conf, T) {
+       if x.assignableTo(conf, T, nil) {
                return true
        }
 
index 8e9e5f36de4194f3538ea76cc47289cd0dc82e0c..f064f6856f24f7dc1b52d0393bd575e0f11de2be 100644 (file)
@@ -156,7 +156,7 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
                assert(lhs == nil || lhs[0] == obj)
                var x operand
                check.expr(&x, init)
-               check.initVar(obj, &x, false)
+               check.initVar(obj, &x, "variable declaration")
                return
        }
 
index 7e0be43e723e4fec13964bfe58065e630b26d5bb..603211257dc572b32286286b76a5be669debf2c7 100644 (file)
@@ -48,7 +48,7 @@ func testEval(t *testing.T, fset *token.FileSet, pkg *Package, pos token.Pos, ex
        // compare values
        gotStr := ""
        if gotTv.Value != nil {
-               gotStr = gotTv.Value.String()
+               gotStr = gotTv.Value.ExactString()
        }
        if gotStr != valStr {
                t.Errorf("Eval(%q) got value %s, want %s", expr, gotStr, valStr)
index 7d00dd5fa5d194f32b1eda55d99c67abf9f08c98..942d3fd5f737040da4a63a12969cddb26cb07f8e 100644 (file)
@@ -180,25 +180,27 @@ func roundFloat64(x constant.Value) constant.Value {
 }
 
 // representableConst reports whether x can be represented as
-// value of the given basic type kind and for the configuration
+// value of the given basic type and for the configuration
 // provided (only needed for int/uint sizes).
 //
 // If rounded != nil, *rounded is set to the rounded value of x for
 // representable floating-point values; it is left alone otherwise.
 // It is ok to provide the addressof the first argument for rounded.
-func representableConst(x constant.Value, conf *Config, as BasicKind, rounded *constant.Value) bool {
-       switch x.Kind() {
-       case constant.Unknown:
-               return true
-
-       case constant.Bool:
-               return as == Bool || as == UntypedBool
+func representableConst(x constant.Value, conf *Config, typ *Basic, rounded *constant.Value) bool {
+       if x.Kind() == constant.Unknown {
+               return true // avoid follow-up errors
+       }
 
-       case constant.Int:
+       switch {
+       case isInteger(typ):
+               x := constant.ToInt(x)
+               if x.Kind() != constant.Int {
+                       return false
+               }
                if x, ok := constant.Int64Val(x); ok {
-                       switch as {
+                       switch typ.kind {
                        case Int:
-                               var s = uint(conf.sizeof(Typ[as])) * 8
+                               var s = uint(conf.sizeof(typ)) * 8
                                return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
                        case Int8:
                                const s = 8
@@ -209,10 +211,10 @@ func representableConst(x constant.Value, conf *Config, as BasicKind, rounded *c
                        case Int32:
                                const s = 32
                                return -1<<(s-1) <= x && x <= 1<<(s-1)-1
-                       case Int64:
+                       case Int64, UntypedInt:
                                return true
                        case Uint, Uintptr:
-                               if s := uint(conf.sizeof(Typ[as])) * 8; s < 64 {
+                               if s := uint(conf.sizeof(typ)) * 8; s < 64 {
                                        return 0 <= x && x <= int64(1)<<s-1
                                }
                                return 0 <= x
@@ -227,44 +229,28 @@ func representableConst(x constant.Value, conf *Config, as BasicKind, rounded *c
                                return 0 <= x && x <= 1<<s-1
                        case Uint64:
                                return 0 <= x
-                       case Float32, Float64, Complex64, Complex128,
-                               UntypedInt, UntypedFloat, UntypedComplex:
-                               return true
+                       default:
+                               unreachable()
                        }
                }
-
-               n := constant.BitLen(x)
-               switch as {
+               // x does not fit into int64
+               switch n := constant.BitLen(x); typ.kind {
                case Uint, Uintptr:
-                       var s = uint(conf.sizeof(Typ[as])) * 8
+                       var s = uint(conf.sizeof(typ)) * 8
                        return constant.Sign(x) >= 0 && n <= int(s)
                case Uint64:
                        return constant.Sign(x) >= 0 && n <= 64
-               case Float32, Complex64:
-                       if rounded == nil {
-                               return fitsFloat32(x)
-                       }
-                       r := roundFloat32(x)
-                       if r != nil {
-                               *rounded = r
-                               return true
-                       }
-               case Float64, Complex128:
-                       if rounded == nil {
-                               return fitsFloat64(x)
-                       }
-                       r := roundFloat64(x)
-                       if r != nil {
-                               *rounded = r
-                               return true
-                       }
-               case UntypedInt, UntypedFloat, UntypedComplex:
+               case UntypedInt:
                        return true
                }
 
-       case constant.Float:
-               switch as {
-               case Float32, Complex64:
+       case isFloat(typ):
+               x := constant.ToFloat(x)
+               if x.Kind() != constant.Float {
+                       return false
+               }
+               switch typ.kind {
+               case Float32:
                        if rounded == nil {
                                return fitsFloat32(x)
                        }
@@ -273,7 +259,7 @@ func representableConst(x constant.Value, conf *Config, as BasicKind, rounded *c
                                *rounded = r
                                return true
                        }
-               case Float64, Complex128:
+               case Float64:
                        if rounded == nil {
                                return fitsFloat64(x)
                        }
@@ -282,12 +268,18 @@ func representableConst(x constant.Value, conf *Config, as BasicKind, rounded *c
                                *rounded = r
                                return true
                        }
-               case UntypedFloat, UntypedComplex:
+               case UntypedFloat:
                        return true
+               default:
+                       unreachable()
                }
 
-       case constant.Complex:
-               switch as {
+       case isComplex(typ):
+               x := constant.ToComplex(x)
+               if x.Kind() != constant.Complex {
+                       return false
+               }
+               switch typ.kind {
                case Complex64:
                        if rounded == nil {
                                return fitsFloat32(constant.Real(x)) && fitsFloat32(constant.Imag(x))
@@ -310,13 +302,15 @@ func representableConst(x constant.Value, conf *Config, as BasicKind, rounded *c
                        }
                case UntypedComplex:
                        return true
+               default:
+                       unreachable()
                }
 
-       case constant.String:
-               return as == String || as == UntypedString
+       case isString(typ):
+               return x.Kind() == constant.String
 
-       default:
-               unreachable()
+       case isBoolean(typ):
+               return x.Kind() == constant.Bool
        }
 
        return false
@@ -325,7 +319,7 @@ func representableConst(x constant.Value, conf *Config, as BasicKind, rounded *c
 // representable checks that a constant operand is representable in the given basic type.
 func (check *Checker) representable(x *operand, typ *Basic) {
        assert(x.mode == constant_)
-       if !representableConst(x.val, check.conf, typ.kind, &x.val) {
+       if !representableConst(x.val, check.conf, typ, &x.val) {
                var msg string
                if isNumeric(x.typ) && isNumeric(typ) {
                        // numeric conversion : error msg
@@ -498,8 +492,6 @@ func (check *Checker) convertUntyped(x *operand, target Type) {
                                return
                        }
                        // expression value may have been rounded - update if needed
-                       // TODO(gri) A floating-point value may silently underflow to
-                       // zero. If it was negative, the sign is lost. See issue 6898.
                        check.updateExprVal(x.expr, x.val)
                } else {
                        // Non-constant untyped values may appear as the
@@ -570,7 +562,7 @@ func (check *Checker) comparison(x, y *operand, op token.Token) {
        // spec: "In any comparison, the first operand must be assignable
        // to the type of the second operand, or vice versa."
        err := ""
-       if x.assignableTo(check.conf, y.typ) || y.assignableTo(check.conf, x.typ) {
+       if x.assignableTo(check.conf, y.typ, nil) || y.assignableTo(check.conf, x.typ, nil) {
                defined := false
                switch op {
                case token.EQL, token.NEQ:
@@ -618,12 +610,19 @@ func (check *Checker) comparison(x, y *operand, op token.Token) {
        x.typ = Typ[UntypedBool]
 }
 
-func (check *Checker) shift(x, y *operand, op token.Token) {
+func (check *Checker) shift(x, y *operand, e *ast.BinaryExpr, op token.Token) {
        untypedx := isUntyped(x.typ)
 
-       // The lhs must be of integer type or be representable
-       // as an integer; otherwise the shift has no chance.
-       if !x.isInteger() {
+       var xval constant.Value
+       if x.mode == constant_ {
+               xval = constant.ToInt(x.val)
+       }
+
+       if isInteger(x.typ) || untypedx && xval != nil && xval.Kind() == constant.Int {
+               // The lhs is of integer type or an untyped constant representable
+               // as an integer. Nothing to do.
+       } else {
+               // shift has no chance
                check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
                x.mode = invalid
                return
@@ -633,7 +632,7 @@ func (check *Checker) shift(x, y *operand, op token.Token) {
        // integer type or be an untyped constant that can be converted to
        // unsigned integer type."
        switch {
-       case isInteger(y.typ) && isUnsigned(y.typ):
+       case isUnsigned(y.typ):
                // nothing to do
        case isUntyped(y.typ):
                check.convertUntyped(y, Typ[UntypedInt])
@@ -650,14 +649,15 @@ func (check *Checker) shift(x, y *operand, op token.Token) {
        if x.mode == constant_ {
                if y.mode == constant_ {
                        // rhs must be an integer value
-                       if !y.isInteger() {
+                       yval := constant.ToInt(y.val)
+                       if yval.Kind() != constant.Int {
                                check.invalidOp(y.pos(), "shift count %s must be unsigned integer", y)
                                x.mode = invalid
                                return
                        }
                        // rhs must be within reasonable bounds
                        const stupidShift = 1023 - 1 + 52 // so we can express smallestFloat64
-                       s, ok := constant.Uint64Val(y.val)
+                       s, ok := constant.Uint64Val(yval)
                        if !ok || s > stupidShift {
                                check.invalidOp(y.pos(), "stupid shift count %s", y)
                                x.mode = invalid
@@ -670,7 +670,16 @@ func (check *Checker) shift(x, y *operand, op token.Token) {
                        if !isInteger(x.typ) {
                                x.typ = Typ[UntypedInt]
                        }
-                       x.val = constant.Shift(x.val, op, uint(s))
+                       // x is a constant so xval != nil and it must be of Int kind.
+                       x.val = constant.Shift(xval, op, uint(s))
+                       // Typed constants must be representable in
+                       // their type after each constant operation.
+                       if isTyped(x.typ) {
+                               if e != nil {
+                                       x.expr = e // for better error message
+                               }
+                               check.representable(x, x.typ.Underlying().(*Basic))
+                       }
                        return
                }
 
@@ -681,13 +690,24 @@ func (check *Checker) shift(x, y *operand, op token.Token) {
                        // constant is what it would be if the shift expression
                        // were replaced by its left operand alone.".
                        //
-                       // Delay operand checking until we know the final type:
-                       // The lhs expression must be in the untyped map, mark
-                       // the entry as lhs shift operand.
-                       info, found := check.untyped[x.expr]
-                       assert(found)
-                       info.isLhs = true
-                       check.untyped[x.expr] = info
+                       // Delay operand checking until we know the final type
+                       // by marking the lhs expression as lhs shift operand.
+                       //
+                       // Usually (in correct programs), the lhs expression
+                       // is in the untyped map. However, it is possible to
+                       // create incorrect programs where the same expression
+                       // is evaluated twice (via a declaration cycle) such
+                       // that the lhs expression type is determined in the
+                       // first round and thus deleted from the map, and then
+                       // not found in the second round (double insertion of
+                       // the same expr node still just leads to one entry for
+                       // that node, and it can only be deleted once).
+                       // Be cautious and check for presence of entry.
+                       // Example: var e, f = int(1<<""[f]) // issue 11347
+                       if info, found := check.untyped[x.expr]; found {
+                               info.isLhs = true
+                               check.untyped[x.expr] = info
+                       }
                        // keep x's type
                        x.mode = value
                        return
@@ -742,7 +762,7 @@ func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, o
        }
 
        if isShift(op) {
-               check.shift(x, &y, op)
+               check.shift(x, &y, e, op)
                return
        }
 
@@ -783,12 +803,16 @@ func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, o
        }
 
        if x.mode == constant_ && y.mode == constant_ {
+               xval := x.val
+               yval := y.val
                typ := x.typ.Underlying().(*Basic)
                // force integer division of integer operands
                if op == token.QUO && isInteger(typ) {
+                       xval = constant.ToInt(xval)
+                       yval = constant.ToInt(yval)
                        op = token.QUO_ASSIGN
                }
-               x.val = constant.BinaryOp(x.val, op, y.val)
+               x.val = constant.BinaryOp(xval, op, yval)
                // Typed constants must be representable in
                // their type after each constant operation.
                if isTyped(typ) {
@@ -832,7 +856,7 @@ func (check *Checker) index(index ast.Expr, max int64) (i int64, valid bool) {
                        check.invalidArg(x.pos(), "index %s must not be negative", &x)
                        return
                }
-               i, valid = constant.Int64Val(x.val)
+               i, valid = constant.Int64Val(constant.ToInt(x.val))
                if !valid || max >= 0 && i >= max {
                        check.errorf(x.pos(), "index %s is out of bounds", &x)
                        return i, false
@@ -887,9 +911,7 @@ func (check *Checker) indexedElts(elts []ast.Expr, typ Type, length int64) int64
                // check element against composite literal element type
                var x operand
                check.exprWithHint(&x, eval, typ)
-               if !check.assignment(&x, typ) && x.mode != invalid {
-                       check.errorf(x.pos(), "cannot use %s as %s value in array or slice literal", &x, typ)
-               }
+               check.assignment(&x, typ, "array or slice literal")
        }
        return max
 }
@@ -1051,12 +1073,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
                                        visited[i] = true
                                        check.expr(x, kv.Value)
                                        etyp := fld.typ
-                                       if !check.assignment(x, etyp) {
-                                               if x.mode != invalid {
-                                                       check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp)
-                                               }
-                                               continue
-                                       }
+                                       check.assignment(x, etyp, "struct literal")
                                }
                        } else {
                                // no element must have a key
@@ -1077,12 +1094,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
                                                continue
                                        }
                                        etyp := fld.typ
-                                       if !check.assignment(x, etyp) {
-                                               if x.mode != invalid {
-                                                       check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp)
-                                               }
-                                               continue
-                                       }
+                                       check.assignment(x, etyp, "struct literal")
                                }
                                if len(e.Elts) < len(fields) {
                                        check.error(e.Rbrace, "too few values in struct literal")
@@ -1109,10 +1121,8 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
                                        continue
                                }
                                check.exprWithHint(x, kv.Key, utyp.key)
-                               if !check.assignment(x, utyp.key) {
-                                       if x.mode != invalid {
-                                               check.errorf(x.pos(), "cannot use %s as %s key in map literal", x, utyp.key)
-                                       }
+                               check.assignment(x, utyp.key, "map literal")
+                               if x.mode == invalid {
                                        continue
                                }
                                if x.mode == constant_ {
@@ -1136,12 +1146,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
                                        }
                                }
                                check.exprWithHint(x, kv.Value, utyp.elem)
-                               if !check.assignment(x, utyp.elem) {
-                                       if x.mode != invalid {
-                                               check.errorf(x.pos(), "cannot use %s as %s value in map literal", x, utyp.elem)
-                                       }
-                                       continue
-                               }
+                               check.assignment(x, utyp.elem, "map literal")
                        }
 
                default:
@@ -1209,10 +1214,8 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
                case *Map:
                        var key operand
                        check.expr(&key, e.Index)
-                       if !check.assignment(&key, typ.key) {
-                               if key.mode != invalid {
-                                       check.invalidOp(key.pos(), "cannot use %s as map index of type %s", &key, typ.key)
-                               }
+                       check.assignment(&key, typ.key, "map index")
+                       if x.mode == invalid {
                                goto Error
                        }
                        x.mode = mapindex
@@ -1245,7 +1248,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
                switch typ := x.typ.Underlying().(type) {
                case *Basic:
                        if isString(typ) {
-                               if slice3(e) {
+                               if e.Slice3 {
                                        check.invalidOp(x.pos(), "3-index slice of string")
                                        goto Error
                                }
@@ -1289,14 +1292,14 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
                x.mode = value
 
                // spec: "Only the first index may be omitted; it defaults to 0."
-               if slice3(e) && (e.High == nil || sliceMax(e) == nil) {
+               if e.Slice3 && (e.High == nil || e.Max == nil) {
                        check.error(e.Rbrack, "2nd and 3rd index required in 3-index slice")
                        goto Error
                }
 
                // check indices
                var ind [3]int64
-               for i, expr := range []ast.Expr{e.Low, e.High, sliceMax(e)} {
+               for i, expr := range []ast.Expr{e.Low, e.High, e.Max} {
                        x := int64(-1)
                        switch {
                        case expr != nil:
@@ -1442,45 +1445,64 @@ func (check *Checker) typeAssertion(pos token.Pos, x *operand, xtyp *Interface,
        check.errorf(pos, "%s cannot have dynamic type %s (%s %s)", x, T, msg, method.name)
 }
 
+func (check *Checker) singleValue(x *operand) {
+       if x.mode == value {
+               // tuple types are never named - no need for underlying type below
+               if t, ok := x.typ.(*Tuple); ok {
+                       assert(t.Len() != 1)
+                       check.errorf(x.pos(), "%d-valued %s where single value is expected", t.Len(), x)
+                       x.mode = invalid
+               }
+       }
+}
+
 // expr typechecks expression e and initializes x with the expression value.
+// The result must be a single value.
 // If an error occurred, x.mode is set to invalid.
 //
 func (check *Checker) expr(x *operand, e ast.Expr) {
+       check.multiExpr(x, e)
+       check.singleValue(x)
+}
+
+// multiExpr is like expr but the result may be a multi-value.
+func (check *Checker) multiExpr(x *operand, e ast.Expr) {
        check.rawExpr(x, e, nil)
        var msg string
        switch x.mode {
        default:
                return
        case novalue:
-               msg = "used as value"
+               msg = "%s used as value"
        case builtin:
-               msg = "must be called"
+               msg = "%s must be called"
        case typexpr:
-               msg = "is not an expression"
+               msg = "%s is not an expression"
        }
-       check.errorf(x.pos(), "%s %s", x, msg)
+       check.errorf(x.pos(), msg, x)
        x.mode = invalid
 }
 
-// exprWithHint typechecks expression e and initializes x with the expression value.
+// exprWithHint typechecks expression e and initializes x with the expression value;
+// hint is the type of a composite literal element.
 // If an error occurred, x.mode is set to invalid.
-// If hint != nil, it is the type of a composite literal element.
 //
 func (check *Checker) exprWithHint(x *operand, e ast.Expr, hint Type) {
        assert(hint != nil)
        check.rawExpr(x, e, hint)
+       check.singleValue(x)
        var msg string
        switch x.mode {
        default:
                return
        case novalue:
-               msg = "used as value"
+               msg = "%s used as value"
        case builtin:
-               msg = "must be called"
+               msg = "%s must be called"
        case typexpr:
-               msg = "is not an expression"
+               msg = "%s is not an expression"
        }
-       check.errorf(x.pos(), "%s %s", x, msg)
+       check.errorf(x.pos(), msg, x)
        x.mode = invalid
 }
 
@@ -1489,6 +1511,7 @@ func (check *Checker) exprWithHint(x *operand, e ast.Expr, hint Type) {
 //
 func (check *Checker) exprOrType(x *operand, e ast.Expr) {
        check.rawExpr(x, e, nil)
+       check.singleValue(x)
        if x.mode == novalue {
                check.errorf(x.pos(), "%s used as value or type", x)
                x.mode = invalid
diff --git a/libgo/go/go/types/go11.go b/libgo/go/go/types/go11.go
deleted file mode 100644 (file)
index cf41cab..0000000
+++ /dev/null
@@ -1,17 +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 !go1.2
-
-package types
-
-import "go/ast"
-
-func slice3(x *ast.SliceExpr) bool {
-       return false
-}
-
-func sliceMax(x *ast.SliceExpr) ast.Expr {
-       return nil
-}
diff --git a/libgo/go/go/types/go12.go b/libgo/go/go/types/go12.go
deleted file mode 100644 (file)
index 2017442..0000000
+++ /dev/null
@@ -1,17 +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 go1.2
-
-package types
-
-import "go/ast"
-
-func slice3(x *ast.SliceExpr) bool {
-       return x.Slice3
-}
-
-func sliceMax(x *ast.SliceExpr) ast.Expr {
-       return x.Max
-}
diff --git a/libgo/go/go/types/gotype.go b/libgo/go/go/types/gotype.go
new file mode 100644 (file)
index 0000000..0a36c08
--- /dev/null
@@ -0,0 +1,322 @@
+// 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 ignore
+
+// Build this command explicitly: go build gotype.go
+
+/*
+The gotype command does syntactic and semantic analysis of Go files
+and packages like the front-end of a Go compiler. Errors are reported
+if the analysis fails; otherwise gotype is quiet (unless -v is set).
+
+Without a list of paths, gotype reads from standard input, which
+must provide a single Go source file defining a complete package.
+
+If a single path is specified that is a directory, gotype checks
+the Go files in that directory; they must all belong to the same
+package.
+
+Otherwise, each path must be the filename of Go file belonging to
+the same package.
+
+Usage:
+       gotype [flags] [path...]
+
+The flags are:
+       -a
+               use all (incl. _test.go) files when processing a directory
+       -e
+               report all errors (not just the first 10)
+       -v
+               verbose mode
+       -c
+               compiler used to compile packages (gc or gccgo); default: gc
+               (gotype based on Go1.5 and up only)
+       -gccgo
+               use gccimporter instead of gcimporter
+               (gotype based on Go1.4 and before only)
+
+Debugging flags:
+       -seq
+               parse sequentially, rather than in parallel
+       -ast
+               print AST (forces -seq)
+       -trace
+               print parse trace (forces -seq)
+       -comments
+               parse comments (ignored unless -ast or -trace is provided)
+
+Examples:
+
+To check the files a.go, b.go, and c.go:
+
+       gotype a.go b.go c.go
+
+To check an entire package in the directory dir and print the processed files:
+
+       gotype -v dir
+
+To check an entire package including tests in the local directory:
+
+       gotype -a .
+
+To verify the output of a pipe:
+
+       echo "package foo" | gotype
+
+*/
+package main
+
+import (
+       "flag"
+       "fmt"
+       "go/ast"
+       "go/build"
+       "go/importer"
+       "go/parser"
+       "go/scanner"
+       "go/token"
+       "go/types"
+       "io/ioutil"
+       "os"
+       "path/filepath"
+       "time"
+)
+
+var (
+       // main operation modes
+       allFiles  = flag.Bool("a", false, "use all (incl. _test.go) files when processing a directory")
+       allErrors = flag.Bool("e", false, "report all errors (not just the first 10)")
+       verbose   = flag.Bool("v", false, "verbose mode")
+       gccgo     = flag.Bool("gccgo", false, "use gccgoimporter instead of gcimporter")
+
+       // debugging support
+       sequential    = flag.Bool("seq", false, "parse sequentially, rather than in parallel")
+       printAST      = flag.Bool("ast", false, "print AST (forces -seq)")
+       printTrace    = flag.Bool("trace", false, "print parse trace (forces -seq)")
+       parseComments = flag.Bool("comments", false, "parse comments (ignored unless -ast or -trace is provided)")
+)
+
+var (
+       fset       = token.NewFileSet()
+       errorCount = 0
+       parserMode parser.Mode
+       sizes      types.Sizes
+)
+
+func initParserMode() {
+       if *allErrors {
+               parserMode |= parser.AllErrors
+       }
+       if *printTrace {
+               parserMode |= parser.Trace
+       }
+       if *parseComments && (*printAST || *printTrace) {
+               parserMode |= parser.ParseComments
+       }
+}
+
+func initSizes() {
+       wordSize := 8
+       maxAlign := 8
+       switch build.Default.GOARCH {
+       case "386", "arm":
+               wordSize = 4
+               maxAlign = 4
+               // add more cases as needed
+       }
+       sizes = &types.StdSizes{WordSize: int64(wordSize), MaxAlign: int64(maxAlign)}
+}
+
+func usage() {
+       fmt.Fprintln(os.Stderr, "usage: gotype [flags] [path ...]")
+       flag.PrintDefaults()
+       os.Exit(2)
+}
+
+func report(err error) {
+       scanner.PrintError(os.Stderr, err)
+       if list, ok := err.(scanner.ErrorList); ok {
+               errorCount += len(list)
+               return
+       }
+       errorCount++
+}
+
+// parse may be called concurrently
+func parse(filename string, src interface{}) (*ast.File, error) {
+       if *verbose {
+               fmt.Println(filename)
+       }
+       file, err := parser.ParseFile(fset, filename, src, parserMode) // ok to access fset concurrently
+       if *printAST {
+               ast.Print(fset, file)
+       }
+       return file, err
+}
+
+func parseStdin() (*ast.File, error) {
+       src, err := ioutil.ReadAll(os.Stdin)
+       if err != nil {
+               return nil, err
+       }
+       return parse("<standard input>", src)
+}
+
+func parseFiles(filenames []string) ([]*ast.File, error) {
+       files := make([]*ast.File, len(filenames))
+
+       if *sequential {
+               for i, filename := range filenames {
+                       var err error
+                       files[i], err = parse(filename, nil)
+                       if err != nil {
+                               return nil, err // leave unfinished goroutines hanging
+                       }
+               }
+       } else {
+               type parseResult struct {
+                       file *ast.File
+                       err  error
+               }
+
+               out := make(chan parseResult)
+               for _, filename := range filenames {
+                       go func(filename string) {
+                               file, err := parse(filename, nil)
+                               out <- parseResult{file, err}
+                       }(filename)
+               }
+
+               for i := range filenames {
+                       res := <-out
+                       if res.err != nil {
+                               return nil, res.err // leave unfinished goroutines hanging
+                       }
+                       files[i] = res.file
+               }
+       }
+
+       return files, nil
+}
+
+func parseDir(dirname string) ([]*ast.File, error) {
+       ctxt := build.Default
+       pkginfo, err := ctxt.ImportDir(dirname, 0)
+       if _, nogo := err.(*build.NoGoError); err != nil && !nogo {
+               return nil, err
+       }
+       filenames := append(pkginfo.GoFiles, pkginfo.CgoFiles...)
+       if *allFiles {
+               filenames = append(filenames, pkginfo.TestGoFiles...)
+       }
+
+       // complete file names
+       for i, filename := range filenames {
+               filenames[i] = filepath.Join(dirname, filename)
+       }
+
+       return parseFiles(filenames)
+}
+
+func getPkgFiles(args []string) ([]*ast.File, error) {
+       if len(args) == 0 {
+               // stdin
+               file, err := parseStdin()
+               if err != nil {
+                       return nil, err
+               }
+               return []*ast.File{file}, nil
+       }
+
+       if len(args) == 1 {
+               // possibly a directory
+               path := args[0]
+               info, err := os.Stat(path)
+               if err != nil {
+                       return nil, err
+               }
+               if info.IsDir() {
+                       return parseDir(path)
+               }
+       }
+
+       // list of files
+       return parseFiles(args)
+}
+
+func checkPkgFiles(files []*ast.File) {
+       compiler := "gc"
+       if *gccgo {
+               compiler = "gccgo"
+       }
+       type bailout struct{}
+       conf := types.Config{
+               FakeImportC: true,
+               Error: func(err error) {
+                       if !*allErrors && errorCount >= 10 {
+                               panic(bailout{})
+                       }
+                       report(err)
+               },
+               Importer: importer.For(compiler, nil),
+               Sizes:    sizes,
+       }
+
+       defer func() {
+               switch p := recover().(type) {
+               case nil, bailout:
+                       // normal return or early exit
+               default:
+                       // re-panic
+                       panic(p)
+               }
+       }()
+
+       const path = "pkg" // any non-empty string will do for now
+       conf.Check(path, fset, files, nil)
+}
+
+func printStats(d time.Duration) {
+       fileCount := 0
+       lineCount := 0
+       fset.Iterate(func(f *token.File) bool {
+               fileCount++
+               lineCount += f.LineCount()
+               return true
+       })
+
+       fmt.Printf(
+               "%s (%d files, %d lines, %d lines/s)\n",
+               d, fileCount, lineCount, int64(float64(lineCount)/d.Seconds()),
+       )
+}
+
+func main() {
+       flag.Usage = usage
+       flag.Parse()
+       if *printAST || *printTrace {
+               *sequential = true
+       }
+       initParserMode()
+       initSizes()
+
+       start := time.Now()
+
+       files, err := getPkgFiles(flag.Args())
+       if err != nil {
+               report(err)
+               os.Exit(2)
+       }
+
+       checkPkgFiles(files)
+       if errorCount > 0 {
+               os.Exit(2)
+       }
+
+       if *verbose {
+               printStats(time.Since(start))
+       }
+}
index cfd51b1d6491c553f0154c6f6f05044ed79fcaf5..bf2a15b26a3258fa5e9b84e1a47b1ec8aba0ae6a 100644 (file)
@@ -24,6 +24,8 @@ var (
 )
 
 func TestHilbert(t *testing.T) {
+       t.Skip("skipping for gccgo--no importer")
+
        // generate source
        src := program(*H, *out)
        if *out != "" {
index 672c78dfc200331ea90a56eee052008e9bcca778..edcc1c0276c8e04970c334d8117351cf9cc44da6 100644 (file)
@@ -11,6 +11,7 @@ import (
        "go/ast"
        "go/importer"
        "go/parser"
+       "internal/testenv"
        "sort"
        "strings"
        "testing"
@@ -19,6 +20,8 @@ import (
 )
 
 func TestIssue5770(t *testing.T) {
+       t.Skip("skipping for gccgo--no importer")
+
        src := `package p; type S struct{T}`
        f, err := parser.ParseFile(fset, "", src, 0)
        if err != nil {
@@ -204,3 +207,90 @@ L7 uses var z int`
                t.Errorf("Unexpected defs/uses\ngot:\n%s\nwant:\n%s", got, want)
        }
 }
+
+// This tests that the package associated with the types.Object.Pkg method
+// is the type's package independent of the order in which the imports are
+// listed in the sources src1, src2 below.
+// The actual issue is in go/internal/gcimporter which has a corresponding
+// test; we leave this test here to verify correct behavior at the go/types
+// level.
+func TestIssue13898(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+
+       const src0 = `
+package main
+
+import "go/types"
+
+func main() {
+       var info types.Info
+       for _, obj := range info.Uses {
+               _ = obj.Pkg()
+       }
+}
+`
+       // like src0, but also imports go/importer
+       const src1 = `
+package main
+
+import (
+       "go/types"
+       _ "go/importer"
+)
+
+func main() {
+       var info types.Info
+       for _, obj := range info.Uses {
+               _ = obj.Pkg()
+       }
+}
+`
+       // like src1 but with different import order
+       // (used to fail with this issue)
+       const src2 = `
+package main
+
+import (
+       _ "go/importer"
+       "go/types"
+)
+
+func main() {
+       var info types.Info
+       for _, obj := range info.Uses {
+               _ = obj.Pkg()
+       }
+}
+`
+       f := func(test, src string) {
+               f, err := parser.ParseFile(fset, "", src, 0)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               cfg := Config{Importer: importer.Default()}
+               info := Info{Uses: make(map[*ast.Ident]Object)}
+               _, err = cfg.Check("main", fset, []*ast.File{f}, &info)
+               if err != nil {
+                       t.Fatal(err)
+               }
+
+               var pkg *Package
+               count := 0
+               for id, obj := range info.Uses {
+                       if id.Name == "Pkg" {
+                               pkg = obj.Pkg()
+                               count++
+                       }
+               }
+               if count != 1 {
+                       t.Fatalf("%s: got %d entries named Pkg; want 1", test, count)
+               }
+               if pkg.Name() != "types" {
+                       t.Fatalf("%s: got %v; want package types", test, pkg)
+               }
+       }
+
+       f("src0", src0)
+       f("src1", src1)
+       f("src2", src2)
+}
index d3bab51b04a0bfbd11c302fe0b4b33b13f8ea18f..b2f16b64d804242e9caeedea99aff77f7bd10cd9 100644 (file)
@@ -166,13 +166,6 @@ func (x *operand) String() string {
 
 // setConst sets x to the untyped constant for literal lit.
 func (x *operand) setConst(tok token.Token, lit string) {
-       val := constant.MakeFromLiteral(lit, tok, 0)
-       if val == nil {
-               // TODO(gri) Should we make it an unknown constant instead?
-               x.mode = invalid
-               return
-       }
-
        var kind BasicKind
        switch tok {
        case token.INT:
@@ -185,11 +178,13 @@ func (x *operand) setConst(tok token.Token, lit string) {
                kind = UntypedRune
        case token.STRING:
                kind = UntypedString
+       default:
+               unreachable()
        }
 
        x.mode = constant_
        x.typ = Typ[kind]
-       x.val = val
+       x.val = constant.MakeFromLiteral(lit, tok, 0)
 }
 
 // isNil reports whether x is the nil value.
@@ -202,7 +197,9 @@ func (x *operand) isNil() bool {
 //           overlapping in functionality. Need to simplify and clean up.
 
 // assignableTo reports whether x is assignable to a variable of type T.
-func (x *operand) assignableTo(conf *Config, T Type) bool {
+// If the result is false and a non-nil reason is provided, it may be set
+// to a more detailed explanation of the failure (result != "").
+func (x *operand) assignableTo(conf *Config, T Type, reason *string) bool {
        if x.mode == invalid || T == Typ[Invalid] {
                return true // avoid spurious errors
        }
@@ -217,51 +214,17 @@ func (x *operand) assignableTo(conf *Config, T Type) bool {
        Vu := V.Underlying()
        Tu := T.Underlying()
 
-       // T is an interface type and x implements T
-       // (Do this check first as it might succeed early.)
-       if Ti, ok := Tu.(*Interface); ok {
-               if Implements(x.typ, Ti) {
-                       return true
-               }
-       }
-
-       // x's type V and T have identical underlying types
-       // and at least one of V or T is not a named type
-       if Identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
-               return true
-       }
-
-       // x is a bidirectional channel value, T is a channel
-       // type, x's type V and T have identical element types,
-       // and at least one of V or T is not a named type
-       if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
-               if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) {
-                       return !isNamed(V) || !isNamed(T)
-               }
-       }
-
-       // x is the predeclared identifier nil and T is a pointer,
-       // function, slice, map, channel, or interface type
-       if x.isNil() {
-               switch t := Tu.(type) {
-               case *Basic:
-                       if t.kind == UnsafePointer {
-                               return true
-                       }
-               case *Pointer, *Signature, *Slice, *Map, *Chan, *Interface:
-                       return true
-               }
-               return false
-       }
-
-       // x is an untyped constant representable by a value of type T
+       // x is an untyped value representable by a value of type T
        // TODO(gri) This is borrowing from checker.convertUntyped and
        //           checker.representable. Need to clean up.
        if isUntyped(Vu) {
                switch t := Tu.(type) {
                case *Basic:
+                       if x.isNil() && t.kind == UnsafePointer {
+                               return true
+                       }
                        if x.mode == constant_ {
-                               return representableConst(x.val, conf, t.kind, nil)
+                               return representableConst(x.val, conf, t, nil)
                        }
                        // The result of a comparison is an untyped boolean,
                        // but may not be a constant.
@@ -274,14 +237,37 @@ func (x *operand) assignableTo(conf *Config, T Type) bool {
                        return x.isNil()
                }
        }
+       // Vu is typed
 
-       return false
-}
+       // x's type V and T have identical underlying types
+       // and at least one of V or T is not a named type
+       if Identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
+               return true
+       }
+
+       // T is an interface type and x implements T
+       if Ti, ok := Tu.(*Interface); ok {
+               if m, wrongType := MissingMethod(x.typ, Ti, true); m != nil /* Implements(x.typ, Ti) */ {
+                       if reason != nil {
+                               if wrongType {
+                                       *reason = "wrong type for method " + m.Name()
+                               } else {
+                                       *reason = "missing method " + m.Name()
+                               }
+                       }
+                       return false
+               }
+               return true
+       }
+
+       // x is a bidirectional channel value, T is a channel
+       // type, x's type V and T have identical element types,
+       // and at least one of V or T is not a named type
+       if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
+               if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) {
+                       return !isNamed(V) || !isNamed(T)
+               }
+       }
 
-// isInteger reports whether x is value of integer type
-// or an untyped constant representable as an integer.
-func (x *operand) isInteger() bool {
-       return x.mode == invalid ||
-               isInteger(x.typ) ||
-               isUntyped(x.typ) && x.mode == constant_ && representableConst(x.val, nil, UntypedInt, nil) // no *Config required for UntypedInt
+       return false
 }
index 48fe8398fe64d4ff8ca10153bf82661a4e975c6d..4a432b549600679ca5f5e675672a4c6b70256434 100644 (file)
@@ -36,6 +36,9 @@ func (pkg *Package) Path() string { return pkg.path }
 // Name returns the package name.
 func (pkg *Package) Name() string { return pkg.name }
 
+// SetName sets the package name.
+func (pkg *Package) SetName(name string) { pkg.name = name }
+
 // Scope returns the (complete or incomplete) package scope
 // holding the objects declared at package level (TypeNames,
 // Consts, Vars, and Funcs).
index c31ef423d9a4a74d136d1734103efdcf80e75bf5..14148a585b1047be92147d38a3dd100dc686a474 100644 (file)
@@ -9,7 +9,6 @@ import (
        "go/ast"
        "go/constant"
        "go/token"
-       pathLib "path"
        "strconv"
        "strings"
        "unicode"
@@ -134,6 +133,20 @@ func (check *Checker) collectObjects() {
                pkgImports[imp] = true
        }
 
+       // srcDir is the directory used by the Importer to look up packages.
+       // The typechecker itself doesn't need this information so it is not
+       // explicitly provided. Instead, we extract it from position info of
+       // the source files as needed.
+       // This is the only place where the type-checker (just the importer)
+       // needs to know the actual source location of a file.
+       // TODO(gri) can we come up with a better API instead?
+       var srcDir string
+       if len(check.files) > 0 {
+               // FileName may be "" (typically for tests) in which case
+               // we get "." as the srcDir which is what we would want.
+               srcDir = dir(check.fset.Position(check.files[0].Name.Pos()).Filename)
+       }
+
        for fileNo, file := range check.files {
                // The package identifier denotes the current package,
                // but there is no corresponding package object.
@@ -170,17 +183,20 @@ func (check *Checker) collectObjects() {
                                                        // TODO(gri) shouldn't create a new one each time
                                                        imp = NewPackage("C", "C")
                                                        imp.fake = true
-                                               } else if path == "unsafe" {
-                                                       // package "unsafe" is known to the language
-                                                       imp = Unsafe
                                                } else {
-                                                       if importer := check.conf.Importer; importer != nil {
+                                                       // ordinary import
+                                                       if importer := check.conf.Importer; importer == nil {
+                                                               err = fmt.Errorf("Config.Importer not installed")
+                                                       } else if importerFrom, ok := importer.(ImporterFrom); ok {
+                                                               imp, err = importerFrom.ImportFrom(path, srcDir, 0)
+                                                               if imp == nil && err == nil {
+                                                                       err = fmt.Errorf("Config.Importer.ImportFrom(%s, %s, 0) returned nil but no error", path, pkg.path)
+                                                               }
+                                                       } else {
                                                                imp, err = importer.Import(path)
                                                                if imp == nil && err == nil {
                                                                        err = fmt.Errorf("Config.Importer.Import(%s) returned nil but no error", path)
                                                                }
-                                                       } else {
-                                                               err = fmt.Errorf("Config.Importer not installed")
                                                        }
                                                        if err != nil {
                                                                check.errorf(s.Path.Pos(), "could not import %s (%s)", path, err)
@@ -202,6 +218,11 @@ func (check *Checker) collectObjects() {
                                                name := imp.name
                                                if s.Name != nil {
                                                        name = s.Name.Name
+                                                       if path == "C" {
+                                                               // match cmd/compile (not prescribed by spec)
+                                                               check.errorf(s.Name.Pos(), `cannot rename import "C"`)
+                                                               continue
+                                                       }
                                                        if name == "init" {
                                                                check.errorf(s.Name.Pos(), "cannot declare init - must be func")
                                                                continue
@@ -216,6 +237,11 @@ func (check *Checker) collectObjects() {
                                                        check.recordImplicit(s, obj)
                                                }
 
+                                               if path == "C" {
+                                                       // match cmd/compile (not prescribed by spec)
+                                                       obj.used = true
+                                               }
+
                                                // add import to file scope
                                                if name == "." {
                                                        // merge imported scope with file scope
@@ -425,7 +451,7 @@ func (check *Checker) unusedImports() {
                                // since _ identifiers are not entered into scopes.
                                if !obj.used {
                                        path := obj.imported.path
-                                       base := pathLib.Base(path)
+                                       base := pkgName(path)
                                        if obj.name == base {
                                                check.softErrorf(obj.pos, "%q imported but not used", path)
                                        } else {
@@ -443,3 +469,25 @@ func (check *Checker) unusedImports() {
                }
        }
 }
+
+// pkgName returns the package name (last element) of an import path.
+func pkgName(path string) string {
+       if i := strings.LastIndex(path, "/"); i >= 0 {
+               path = path[i+1:]
+       }
+       return path
+}
+
+// dir makes a good-faith attempt to return the directory
+// portion of path. If path is empty, the result is ".".
+// (Per the go/build package dependency tests, we cannot import
+// path/filepath and simply use filepath.Dir.)
+func dir(path string) string {
+       if i := strings.LastIndexAny(path, "/\\"); i >= 0 {
+               path = path[:i]
+       }
+       if path == "" {
+               path = "."
+       }
+       return path
+}
index 34deae268e3e9945b42512063fdbe0cd494579e8..4da61cc1ebada3ba4e55293e8a6ff1144d9e0663 100644 (file)
@@ -18,16 +18,23 @@ import (
 )
 
 type resolveTestImporter struct {
-       importer Importer
+       importer ImporterFrom
        imported map[string]bool
 }
 
-func (imp *resolveTestImporter) Import(path string) (*Package, error) {
+func (imp *resolveTestImporter) Import(string) (*Package, error) {
+       panic("should not be called")
+}
+
+func (imp *resolveTestImporter) ImportFrom(path, srcDir string, mode ImportMode) (*Package, error) {
+       if mode != 0 {
+               panic("mode must be 0")
+       }
        if imp.importer == nil {
-               imp.importer = importer.Default()
+               imp.importer = importer.Default().(ImporterFrom)
                imp.imported = make(map[string]bool)
        }
-       pkg, err := imp.importer.Import(path)
+       pkg, err := imp.importer.ImportFrom(path, srcDir, mode)
        if err != nil {
                return nil, err
        }
@@ -36,6 +43,8 @@ func (imp *resolveTestImporter) Import(path string) (*Package, error) {
 }
 
 func TestResolveIdents(t *testing.T) {
+       t.Skip("skipping for gccgo--no importer")
+
        testenv.MustHaveGoBuild(t)
 
        sources := []string{
index 10ad06fbca16475b5c55bf471c81291ba8712f97..528fc173f88680a0b8da76d525a2b14ecd479cee 100644 (file)
@@ -21,6 +21,8 @@ import (
 var benchmark = flag.Bool("b", false, "run benchmarks")
 
 func TestSelf(t *testing.T) {
+       t.Skip("skipping for gccgo--no importer")
+
        fset := token.NewFileSet()
        files, err := pkgFiles(fset, ".")
        if err != nil {
index 56fb310c29476eb6234bd0aee2624074e4c5d54e..87c3ce4159767db25b4746083f4c446366faa1ff 100644 (file)
@@ -132,13 +132,8 @@ func (s *StdSizes) Sizeof(T Type) int64 {
                if n == 0 {
                        return 0
                }
-               offsets := t.offsets
-               if t.offsets == nil {
-                       // compute offsets on demand
-                       offsets = s.Offsetsof(t.fields)
-                       t.offsets = offsets
-               }
-               return offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
+               setOffsets(t, s)
+               return t.offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
        case *Interface:
                return s.WordSize * 2
        }
@@ -159,24 +154,27 @@ func (conf *Config) alignof(T Type) int64 {
 }
 
 func (conf *Config) offsetsof(T *Struct) []int64 {
-       offsets := T.offsets
-       if offsets == nil && T.NumFields() > 0 {
+       var offsets []int64
+       if T.NumFields() > 0 {
                // compute offsets on demand
                if s := conf.Sizes; s != nil {
-                       offsets = s.Offsetsof(T.fields)
-                       // sanity checks
-                       if len(offsets) != T.NumFields() {
-                               panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
-                       }
-                       for _, o := range offsets {
-                               if o < 0 {
-                                       panic("Config.Sizes.Offsetsof returned an offset < 0")
+                       calculated := setOffsets(T, s)
+                       offsets = T.offsets
+                       if calculated {
+                               // sanity checks
+                               if len(offsets) != T.NumFields() {
+                                       panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
+                               }
+                               for _, o := range offsets {
+                                       if o < 0 {
+                                               panic("Config.Sizes.Offsetsof returned an offset < 0")
+                                       }
                                }
                        }
                } else {
-                       offsets = stdSizes.Offsetsof(T.fields)
+                       setOffsets(T, &stdSizes)
+                       offsets = T.offsets
                }
-               T.offsets = offsets
        }
        return offsets
 }
@@ -209,3 +207,15 @@ func align(x, a int64) int64 {
        y := x + a - 1
        return y - y%a
 }
+
+// setOffsets sets the offsets of s for the given sizes if necessary.
+// The result is true if the offsets were not set before; otherwise it
+// is false.
+func setOffsets(s *Struct, sizes Sizes) bool {
+       var calculated bool
+       s.offsetsOnce.Do(func() {
+               calculated = true
+               s.offsets = sizes.Offsetsof(s.fields)
+       })
+       return calculated
+}
index c6c946e976a349d85b280b3d796f7f5f7b8de55e..c63bfbb9a4e9ea3b6442ea038a530e39014eeda5 100644 (file)
@@ -11,7 +11,7 @@ import (
        "fmt"
        "go/ast"
        "go/build"
-       "go/importer"
+       // "go/importer"
        "go/parser"
        "go/scanner"
        "go/token"
@@ -33,7 +33,10 @@ var (
 
        // Use the same importer for all std lib tests to
        // avoid repeated importing of the same packages.
-       stdLibImporter = importer.Default()
+
+       // importer.Default panics for gccgo
+       // stdLibImporter = importer.Default()
+       stdLibImporter Importer
 )
 
 func TestStdlib(t *testing.T) {
@@ -76,6 +79,8 @@ func firstComment(filename string) string {
 }
 
 func testTestDir(t *testing.T, path string, ignore ...string) {
+       t.Skip("skipping for gccgo")
+
        files, err := ioutil.ReadDir(path)
        if err != nil {
                t.Fatal(err)
@@ -127,6 +132,10 @@ func testTestDir(t *testing.T, path string, ignore ...string) {
 func TestStdTest(t *testing.T) {
        testenv.MustHaveGoBuild(t)
 
+       if testing.Short() && testenv.Builder() == "" {
+               t.Skip("skipping in short mode")
+       }
+
        // test/recover4.go is only built for Linux and Darwin.
        // TODO(gri) Remove once tests consider +build tags (issue 10370).
        if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
@@ -142,14 +151,15 @@ func TestStdTest(t *testing.T) {
 func TestStdFixed(t *testing.T) {
        testenv.MustHaveGoBuild(t)
 
+       if testing.Short() && testenv.Builder() == "" {
+               t.Skip("skipping in short mode")
+       }
+
        testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"),
                "bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore
-               "bug459.go",      // possibly incorrect test - see issue 6703 (pending spec clarification)
-               "issue3924.go",   // possibly incorrect test - see issue 6671 (pending spec clarification)
-               "issue6889.go",   // gc-specific test
-               "issue7746.go",   // large constants - consumes too much memory
-               "issue11326.go",  // large constants
-               "issue11326b.go", // large constants
+               "issue6889.go",  // gc-specific test
+               "issue7746.go",  // large constants - consumes too much memory
+               "issue11362.go", // canonical import path check
        )
 }
 
@@ -166,6 +176,8 @@ var excluded = map[string]bool{
 
 // typecheck typechecks the given package files.
 func typecheck(t *testing.T, path string, filenames []string) {
+       t.Skip("skipping for gccgo")
+
        fset := token.NewFileSet()
 
        // parse package files
@@ -250,7 +262,7 @@ func pkgFilenames(dir string) ([]string, error) {
 
 func walkDirs(t *testing.T, dir string) {
        // limit run time for short tests
-       if testing.Short() && time.Since(start) >= 750*time.Millisecond {
+       if testing.Short() && time.Since(start) >= 10*time.Millisecond {
                return
        }
 
index 88a1d9b8668fdc7a9255e2412f6b564fa9144d76..e0129cf0e09997b69f8c525a43029224c98311dd 100644 (file)
@@ -155,25 +155,84 @@ func (check *Checker) suspendedCall(keyword string, call *ast.CallExpr) {
        check.errorf(x.pos(), "%s %s %s", keyword, msg, &x)
 }
 
-func (check *Checker) caseValues(x operand /* copy argument (not *operand!) */, values []ast.Expr) {
-       // No duplicate checking for now. See issue 4524.
+// goVal returns the Go value for val, or nil.
+func goVal(val constant.Value) interface{} {
+       // val should exist, but be conservative and check
+       if val == nil {
+               return nil
+       }
+       // Match implementation restriction of other compilers.
+       // gc only checks duplicates for integer, floating-point
+       // and string values, so only create Go values for these
+       // types.
+       switch val.Kind() {
+       case constant.Int:
+               if x, ok := constant.Int64Val(val); ok {
+                       return x
+               }
+               if x, ok := constant.Uint64Val(val); ok {
+                       return x
+               }
+       case constant.Float:
+               if x, ok := constant.Float64Val(val); ok {
+                       return x
+               }
+       case constant.String:
+               return constant.StringVal(val)
+       }
+       return nil
+}
+
+// A valueMap maps a case value (of a basic Go type) to a list of positions
+// where the same case value appeared, together with the corresponding case
+// types.
+// Since two case values may have the same "underlying" value but different
+// types we need to also check the value's types (e.g., byte(1) vs myByte(1))
+// when the switch expression is of interface type.
+type (
+       valueMap  map[interface{}][]valueType // underlying Go value -> valueType
+       valueType struct {
+               pos token.Pos
+               typ Type
+       }
+)
+
+func (check *Checker) caseValues(x *operand, values []ast.Expr, seen valueMap) {
+L:
        for _, e := range values {
-               var y operand
-               check.expr(&y, e)
-               if y.mode == invalid {
-                       return
-               }
-               // TODO(gri) The convertUntyped call pair below appears in other places. Factor!
-               // Order matters: By comparing y against x, error positions are at the case values.
-               check.convertUntyped(&y, x.typ)
-               if y.mode == invalid {
-                       return
-               }
-               check.convertUntyped(&x, y.typ)
-               if x.mode == invalid {
-                       return
+               var v operand
+               check.expr(&v, e)
+               if x.mode == invalid || v.mode == invalid {
+                       continue L
+               }
+               check.convertUntyped(&v, x.typ)
+               if v.mode == invalid {
+                       continue L
+               }
+               // Order matters: By comparing v against x, error positions are at the case values.
+               res := v // keep original v unchanged
+               check.comparison(&res, x, token.EQL)
+               if res.mode == invalid {
+                       continue L
+               }
+               if v.mode != constant_ {
+                       continue L // we're done
+               }
+               // look for duplicate values
+               if val := goVal(v.val); val != nil {
+                       if list := seen[val]; list != nil {
+                               // look for duplicate types for a given value
+                               // (quadratic algorithm, but these lists tend to be very short)
+                               for _, vt := range list {
+                                       if Identical(v.typ, vt.typ) {
+                                               check.errorf(v.pos(), "duplicate case %s in expression switch", &v)
+                                               check.error(vt.pos, "\tprevious case") // secondary error, \t indented
+                                               continue L
+                                       }
+                               }
+                       }
+                       seen[val] = append(seen[val], valueType{v.pos(), v.typ})
                }
-               check.comparison(&y, &x, token.EQL)
        }
 }
 
@@ -182,15 +241,19 @@ L:
        for _, e := range types {
                T = check.typOrNil(e)
                if T == Typ[Invalid] {
-                       continue
+                       continue L
                }
-               // complain about duplicate types
-               // TODO(gri) use a type hash to avoid quadratic algorithm
+               // look for duplicate types
+               // (quadratic algorithm, but type switches tend to be reasonably small)
                for t, pos := range seen {
                        if T == nil && t == nil || T != nil && t != nil && Identical(T, t) {
                                // talk about "case" rather than "type" because of nil case
-                               check.error(e.Pos(), "duplicate case in type switch")
-                               check.errorf(pos, "\tprevious case %s", T) // secondary error, \t indented
+                               Ts := "nil"
+                               if T != nil {
+                                       Ts = T.String()
+                               }
+                               check.errorf(e.Pos(), "duplicate case %s in type switch", Ts)
+                               check.error(pos, "\tprevious case") // secondary error, \t indented
                                continue L
                        }
                }
@@ -258,12 +321,20 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
                if ch.mode == invalid || x.mode == invalid {
                        return
                }
-               if tch, ok := ch.typ.Underlying().(*Chan); !ok || tch.dir == RecvOnly || !check.assignment(&x, tch.elem) {
-                       if x.mode != invalid {
-                               check.invalidOp(ch.pos(), "cannot send %s to channel %s", &x, &ch)
-                       }
+
+               tch, ok := ch.typ.Underlying().(*Chan)
+               if !ok {
+                       check.invalidOp(s.Arrow, "cannot send to non-chan type %s", ch.typ)
+                       return
                }
 
+               if tch.dir == RecvOnly {
+                       check.invalidOp(s.Arrow, "cannot send to receive-only type %s", tch)
+                       return
+               }
+
+               check.assignment(&x, tch.elem, "send")
+
        case *ast.IncDecStmt:
                var op token.Token
                switch s.Tok {
@@ -386,8 +457,15 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
                        check.error(s.Cond.Pos(), "non-boolean condition in if statement")
                }
                check.stmt(inner, s.Body)
-               if s.Else != nil {
+               // The parser produces a correct AST but if it was modified
+               // elsewhere the else branch may be invalid. Check again.
+               switch s.Else.(type) {
+               case nil, *ast.BadStmt:
+                       // valid or error already reported
+               case *ast.IfStmt, *ast.BlockStmt:
                        check.stmt(inner, s.Else)
+               default:
+                       check.error(s.Else.Pos(), "invalid else branch in if statement")
                }
 
        case *ast.SwitchStmt:
@@ -399,6 +477,9 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
                var x operand
                if s.Tag != nil {
                        check.expr(&x, s.Tag)
+                       // By checking assignment of x to an invisible temporary
+                       // (as a compiler would), we get all the relevant checks.
+                       check.assignment(&x, nil, "switch expression")
                } else {
                        // spec: "A missing switch expression is
                        // equivalent to the boolean value true."
@@ -410,15 +491,14 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
 
                check.multipleDefaults(s.Body.List)
 
+               seen := make(valueMap) // map of seen case values to positions and types
                for i, c := range s.Body.List {
                        clause, _ := c.(*ast.CaseClause)
                        if clause == nil {
                                check.invalidAST(c.Pos(), "incorrect expression switch case")
                                continue
                        }
-                       if x.mode != invalid {
-                               check.caseValues(x, clause.List)
-                       }
+                       check.caseValues(&x, clause.List, seen)
                        check.openScope(clause, "case")
                        inner := inner
                        if i+1 < len(s.Body.List) {
@@ -701,7 +781,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
                                        x.mode = value
                                        x.expr = lhs // we don't have a better rhs expression to use here
                                        x.typ = typ
-                                       check.initVar(obj, &x, false)
+                                       check.initVar(obj, &x, "range clause")
                                } else {
                                        obj.typ = Typ[Invalid]
                                        obj.used = true // don't complain about unused variable
index 1df8b45b2855315f03bc9789e5c678811a056af1..d8415f1fdf204d2755f250aba9560f4562354000 100644 (file)
@@ -4,9 +4,10 @@
 
 package types
 
-import "sort"
-
-// TODO(gri) Revisit factory functions - make sure they have all relevant parameters.
+import (
+       "sort"
+       "sync"
+)
 
 // A Type represents a type of Go.
 // All types implement the Type interface.
@@ -120,10 +121,10 @@ func (s *Slice) Elem() Type { return s.elem }
 
 // A Struct represents a struct type.
 type Struct struct {
-       fields []*Var
-       tags   []string // field tags; nil if there are no tags
-       // TODO(gri) access to offsets is not threadsafe - fix this
-       offsets []int64 // field offsets in bytes, lazily initialized
+       fields      []*Var
+       tags        []string  // field tags; nil if there are no tags
+       offsets     []int64   // field offsets in bytes, lazily initialized
+       offsetsOnce sync.Once // for threadsafe lazy initialization of offsets
 }
 
 // NewStruct returns a new struct with the given fields and corresponding field tags.
@@ -360,7 +361,7 @@ type Chan struct {
 // A ChanDir value indicates a channel direction.
 type ChanDir int
 
-// The direction of a channel is indicated by one of the following constants.
+// The direction of a channel is indicated by one of these constants.
 const (
        SendRecv ChanDir = iota
        SendOnly
index bd62f4dc229e80b6b52a7710ab6f1d49840597e3..47378e744c06c6e0624ef0af2dffdc4bea08cf97 100644 (file)
@@ -71,7 +71,7 @@ func TypeString(typ Type, qf Qualifier) string {
 // The Qualifier controls the printing of
 // package-level objects, and may be nil.
 func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
-       writeType(buf, typ, qf, make([]Type, 8))
+       writeType(buf, typ, qf, make([]Type, 0, 8))
 }
 
 func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
@@ -272,7 +272,7 @@ func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visi
 // The Qualifier controls the printing of
 // package-level objects, and may be nil.
 func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
-       writeSignature(buf, sig, qf, make([]Type, 8))
+       writeSignature(buf, sig, qf, make([]Type, 0, 8))
 }
 
 func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
index 913e6c735cc3ea6197298052694c954f8887e3ee..52aa6b67e04c7a0b116a4cf4aae660a098737946 100644 (file)
@@ -18,6 +18,7 @@ import (
 const filename = "<src>"
 
 func makePkg(t *testing.T, src string) (*Package, error) {
+       t.Skip("skipping for gccgo--no importer")
        fset := token.NewFileSet()
        file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors)
        if err != nil {
@@ -139,6 +140,7 @@ func TestTypeString(t *testing.T) {
 }
 
 func TestQualifiedTypeString(t *testing.T) {
+       t.Skip("skipping for gccgo--no importer")
        p, _ := pkgFor("p.go", "package p; type T int", nil)
        q, _ := pkgFor("q.go", "package q", nil)
 
@@ -148,6 +150,7 @@ func TestQualifiedTypeString(t *testing.T) {
                this *Package
                want string
        }{
+               {nil, nil, "<nil>"},
                {pT, nil, "p.T"},
                {pT, p, "T"},
                {pT, q, "p.T"},
index c744eeaa0c785bed18c04fc803486b1ff714a610..931b9247124f363498f48faf016a2c974a156b0e 100644 (file)
@@ -373,16 +373,19 @@ func (check *Checker) arrayLength(e ast.Expr) int64 {
                }
                return 0
        }
-       if !x.isInteger() {
-               check.errorf(x.pos(), "array length %s must be integer", &x)
-               return 0
-       }
-       n, ok := constant.Int64Val(x.val)
-       if !ok || n < 0 {
-               check.errorf(x.pos(), "invalid array length %s", &x)
-               return 0
+       if isUntyped(x.typ) || isInteger(x.typ) {
+               if val := constant.ToInt(x.val); val.Kind() == constant.Int {
+                       if representableConst(val, check.conf, Typ[Int], nil) {
+                               if n, ok := constant.Int64Val(val); ok && n >= 0 {
+                                       return n
+                               }
+                               check.errorf(x.pos(), "invalid array length %s", &x)
+                               return 0
+                       }
+               }
        }
-       return n
+       check.errorf(x.pos(), "array length %s must be integer", &x)
+       return 0
 }
 
 func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, variadic bool) {
index 7c80796bf9fdca2e1c1e778237b06280ec0ce385..0c733f751af5742d72977be67ca6960762c00fb3 100644 (file)
@@ -33,6 +33,7 @@ type digest uint32
 func (d *digest) Reset() { *d = 1 }
 
 // New returns a new hash.Hash32 computing the Adler-32 checksum.
+// Its Sum method will lay the value out in big-endian byte order.
 func New() hash.Hash32 {
        d := new(digest)
        d.Reset()
index 234d92968902d9003fdad3db899c3f3b35c8e367..dc5994885f9d5fe9d585a4750bb6b47460eef68e 100644 (file)
@@ -57,11 +57,12 @@ var IEEETable = makeTable(IEEE)
 // slicing8Table is array of 8 Tables
 type slicing8Table [8]Table
 
-// iEEETable8 is the slicing8Table for IEEE
-var iEEETable8 *slicing8Table
-var iEEETable8Once sync.Once
+// ieeeTable8 is the slicing8Table for IEEE
+var ieeeTable8 *slicing8Table
+var ieeeTable8Once sync.Once
 
-// MakeTable returns the Table constructed from the specified polynomial.
+// MakeTable returns a Table constructed from the specified polynomial.
+// The contents of this Table must not be modified.
 func MakeTable(poly uint32) *Table {
        switch poly {
        case IEEE:
@@ -112,10 +113,12 @@ type digest struct {
 
 // New creates a new hash.Hash32 computing the CRC-32 checksum
 // using the polynomial represented by the Table.
+// Its Sum method will lay the value out in big-endian byte order.
 func New(tab *Table) hash.Hash32 { return &digest{0, tab} }
 
 // NewIEEE creates a new hash.Hash32 computing the CRC-32 checksum
 // using the IEEE polynomial.
+// Its Sum method will lay the value out in big-endian byte order.
 func NewIEEE() hash.Hash32 { return New(IEEETable) }
 
 func (d *digest) Size() int { return Size }
@@ -148,15 +151,11 @@ func updateSlicingBy8(crc uint32, tab *slicing8Table, p []byte) uint32 {
 
 // Update returns the result of adding the bytes in p to the crc.
 func Update(crc uint32, tab *Table, p []byte) uint32 {
-       if tab == castagnoliTable {
+       switch tab {
+       case castagnoliTable:
                return updateCastagnoli(crc, p)
-       }
-       // only use slicing-by-8 when input is larger than 4KB
-       if tab == IEEETable && len(p) >= 4096 {
-               iEEETable8Once.Do(func() {
-                       iEEETable8 = makeTable8(IEEE)
-               })
-               return updateSlicingBy8(crc, iEEETable8, p)
+       case IEEETable:
+               return updateIEEE(crc, p)
        }
        return update(crc, tab, p)
 }
diff --git a/libgo/go/hash/crc32/crc32_amd64.go b/libgo/go/hash/crc32/crc32_amd64.go
new file mode 100644 (file)
index 0000000..ab4e2b8
--- /dev/null
@@ -0,0 +1,56 @@
+// 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 crc32
+
+// This file contains the code to call the SSE 4.2 version of the Castagnoli
+// and IEEE CRC.
+
+// haveSSE41/haveSSE42/haveCLMUL are defined in crc_amd64.s and use
+// CPUID to test for SSE 4.1, 4.2 and CLMUL support.
+func haveSSE41() bool
+func haveSSE42() bool
+func haveCLMUL() bool
+
+// castagnoliSSE42 is defined in crc_amd64.s and uses the SSE4.2 CRC32
+// instruction.
+//go:noescape
+func castagnoliSSE42(crc uint32, p []byte) uint32
+
+// ieeeCLMUL is defined in crc_amd64.s and uses the PCLMULQDQ
+// instruction as well as SSE 4.1.
+//go:noescape
+func ieeeCLMUL(crc uint32, p []byte) uint32
+
+var sse42 = haveSSE42()
+var useFastIEEE = haveCLMUL() && haveSSE41()
+
+func updateCastagnoli(crc uint32, p []byte) uint32 {
+       if sse42 {
+               return castagnoliSSE42(crc, p)
+       }
+       return update(crc, castagnoliTable, p)
+}
+
+func updateIEEE(crc uint32, p []byte) uint32 {
+       if useFastIEEE && len(p) >= 64 {
+               left := len(p) & 15
+               do := len(p) - left
+               crc = ^ieeeCLMUL(^crc, p[:do])
+               if left > 0 {
+                       crc = update(crc, IEEETable, p[do:])
+               }
+               return crc
+       }
+
+       // only use slicing-by-8 when input is >= 4KB
+       if len(p) >= 4096 {
+               ieeeTable8Once.Do(func() {
+                       ieeeTable8 = makeTable8(IEEE)
+               })
+               return updateSlicingBy8(crc, ieeeTable8, p)
+       }
+
+       return update(crc, IEEETable, p)
+}
similarity index 62%
rename from libgo/go/hash/crc32/crc32_amd64x.go
rename to libgo/go/hash/crc32/crc32_amd64p32.go
index b7e359930a4ca59e2f3445f01a68bcad2cc984c7..067fbb162f9da79cfd8e592acb4575d4fbb58425 100644 (file)
@@ -2,19 +2,18 @@
 // 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
 // CRC.
 
-// haveSSE42 is defined in crc_amd64.s and uses CPUID to test for SSE 4.2
+// haveSSE42 is defined in crc_amd64p32.s and uses CPUID to test for SSE 4.2
 // support.
 func haveSSE42() bool
 
 // castagnoliSSE42 is defined in crc_amd64.s and uses the SSE4.2 CRC32
 // instruction.
+//go:noescape
 func castagnoliSSE42(crc uint32, p []byte) uint32
 
 var sse42 = haveSSE42()
@@ -25,3 +24,15 @@ func updateCastagnoli(crc uint32, p []byte) uint32 {
        }
        return update(crc, castagnoliTable, p)
 }
+
+func updateIEEE(crc uint32, p []byte) uint32 {
+       // only use slicing-by-8 when input is >= 4KB
+       if len(p) >= 4096 {
+               ieeeTable8Once.Do(func() {
+                       ieeeTable8 = makeTable8(IEEE)
+               })
+               return updateSlicingBy8(crc, ieeeTable8, p)
+       }
+
+       return update(crc, IEEETable, p)
+}
index 416c1b7c556802bd76a4905330f9e555823e38f1..8fc11a75db66643b4e59c0a3418733d8a8990057 100644 (file)
@@ -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 386 arm arm64 ppc64 ppc64le
+// +build 386 arm arm64 mips64 mips64le ppc64 ppc64le
 
 package crc32
 
@@ -12,3 +12,14 @@ package crc32
 func updateCastagnoli(crc uint32, p []byte) uint32 {
        return update(crc, castagnoliTable, p)
 }
+
+func updateIEEE(crc uint32, p []byte) uint32 {
+       // only use slicing-by-8 when input is >= 4KB
+       if len(p) >= 4096 {
+               ieeeTable8Once.Do(func() {
+                       ieeeTable8 = makeTable8(IEEE)
+               })
+               return updateSlicingBy8(crc, ieeeTable8, p)
+       }
+       return update(crc, IEEETable, p)
+}
index 692586798848cbfe6dad7cb386b3fad20ca238e8..54cc56055e48faac50a62f3637a12dcac65cec01 100644 (file)
@@ -24,7 +24,8 @@ const (
 // Table is a 256-word table representing the polynomial for efficient processing.
 type Table [256]uint64
 
-// MakeTable returns the Table constructed from the specified polynomial.
+// MakeTable returns a Table constructed from the specified polynomial.
+// The contents of this Table must not be modified.
 func MakeTable(poly uint64) *Table {
        t := new(Table)
        for i := 0; i < 256; i++ {
@@ -49,6 +50,7 @@ type digest struct {
 
 // New creates a new hash.Hash64 computing the CRC-64 checksum
 // using the polynomial represented by the Table.
+// Its Sum method will lay the value out in big-endian byte order.
 func New(tab *Table) hash.Hash64 { return &digest{0, tab} }
 
 func (d *digest) Size() int { return Size }
index c0206613acdfd08bb6fd4995ab5f2a97dbe394ef..f1fbb25bdf5899a32fc61a24406f4860ed1075ac 100644 (file)
@@ -5,7 +5,7 @@
 // Package fnv implements FNV-1 and FNV-1a, non-cryptographic hash functions
 // created by Glenn Fowler, Landon Curt Noll, and Phong Vo.
 // See
-// http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function.
+// https://en.wikipedia.org/wiki/Fowler-Noll-Vo_hash_function.
 package fnv
 
 import (
@@ -27,24 +27,28 @@ const (
 )
 
 // New32 returns a new 32-bit FNV-1 hash.Hash.
+// Its Sum method will lay the value out in big-endian byte order.
 func New32() hash.Hash32 {
        var s sum32 = offset32
        return &s
 }
 
 // New32a returns a new 32-bit FNV-1a hash.Hash.
+// Its Sum method will lay the value out in big-endian byte order.
 func New32a() hash.Hash32 {
        var s sum32a = offset32
        return &s
 }
 
 // New64 returns a new 64-bit FNV-1 hash.Hash.
+// Its Sum method will lay the value out in big-endian byte order.
 func New64() hash.Hash64 {
        var s sum64 = offset64
        return &s
 }
 
 // New64a returns a new 64-bit FNV-1a hash.Hash.
+// Its Sum method will lay the value out in big-endian byte order.
 func New64a() hash.Hash64 {
        var s sum64a = offset64
        return &s
index f50a4b937a79b3add3565027877bf22cad348cb8..ab6fd1c7b4b3460d29d2a47a693463c2666b1e25 100644 (file)
@@ -57,8 +57,9 @@ var replacementTable = [...]rune{
 // unescapeEntity reads an entity like "&lt;" from b[src:] and writes the
 // corresponding "<" to b[dst:], returning the incremented dst and src cursors.
 // Precondition: b[src] == '&' && dst <= src.
-// attribute should be true if parsing an attribute value.
-func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
+func unescapeEntity(b []byte, dst, src int) (dst1, src1 int) {
+       const attribute = false
+
        // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference
 
        // i starts at 1 because we already know that s[0] == '&'.
@@ -139,14 +140,14 @@ func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
                break
        }
 
-       entityName := string(s[1:i])
-       if entityName == "" {
+       entityName := s[1:i]
+       if len(entityName) == 0 {
                // No-op.
        } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' {
                // No-op.
-       } else if x := entity[entityName]; x != 0 {
+       } else if x := entity[string(entityName)]; x != 0 {
                return dst + utf8.EncodeRune(b[dst:], x), src + i
-       } else if x := entity2[entityName]; x[0] != 0 {
+       } else if x := entity2[string(entityName)]; x[0] != 0 {
                dst1 := dst + utf8.EncodeRune(b[dst:], x[0])
                return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i
        } else if !attribute {
@@ -155,7 +156,7 @@ func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
                        maxLen = longestEntityWithoutSemicolon
                }
                for j := maxLen; j > 1; j-- {
-                       if x := entity[entityName[:j]]; x != 0 {
+                       if x := entity[string(entityName[:j])]; x != 0 {
                                return dst + utf8.EncodeRune(b[dst:], x), src + j + 1
                        }
                }
@@ -166,26 +167,6 @@ func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
        return dst1, src1
 }
 
-// unescape unescapes b's entities in-place, so that "a&lt;b" becomes "a<b".
-func unescape(b []byte) []byte {
-       for i, c := range b {
-               if c == '&' {
-                       dst, src := unescapeEntity(b, i, i, false)
-                       for src < len(b) {
-                               c := b[src]
-                               if c == '&' {
-                                       dst, src = unescapeEntity(b, dst, src, false)
-                               } else {
-                                       b[dst] = c
-                                       dst, src = dst+1, src+1
-                               }
-                       }
-                       return b[0:dst]
-               }
-       }
-       return b
-}
-
 var htmlEscaper = strings.NewReplacer(
        `&`, "&amp;",
        `'`, "&#39;", // "&#39;" is shorter than "&apos;" and apos was not in HTML until HTML5.
@@ -208,8 +189,29 @@ func EscapeString(s string) string {
 // UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
 // always true.
 func UnescapeString(s string) string {
-       if !strings.Contains(s, "&") {
+       i := strings.IndexByte(s, '&')
+
+       if i < 0 {
                return s
        }
-       return string(unescape([]byte(s)))
+
+       b := []byte(s)
+       dst, src := unescapeEntity(b, i, i)
+       for len(s[src:]) > 0 {
+               if s[src] == '&' {
+                       i = 0
+               } else {
+                       i = strings.IndexByte(s[src:], '&')
+               }
+               if i < 0 {
+                       dst += copy(b[dst:], s[src:])
+                       break
+               }
+
+               if i > 0 {
+                       copy(b[dst:], s[src:src+i])
+               }
+               dst, src = unescapeEntity(b, dst+i, src+i)
+       }
+       return string(b[:dst])
 }
index 3702626a3dccfdb8315925eab22869ac2aefcda4..8b51a55409fa55ee04149b31bafbe4657312d138 100644 (file)
@@ -118,8 +118,10 @@ func TestUnescapeEscape(t *testing.T) {
 }
 
 var (
-       benchEscapeData = strings.Repeat("AAAAA < BBBBB > CCCCC & DDDDD ' EEEEE \" ", 100)
-       benchEscapeNone = strings.Repeat("AAAAA x BBBBB x CCCCC x DDDDD x EEEEE x ", 100)
+       benchEscapeData     = strings.Repeat("AAAAA < BBBBB > CCCCC & DDDDD ' EEEEE \" ", 100)
+       benchEscapeNone     = strings.Repeat("AAAAA x BBBBB x CCCCC x DDDDD x EEEEE x ", 100)
+       benchUnescapeSparse = strings.Repeat(strings.Repeat("AAAAA x BBBBB x CCCCC x DDDDD x EEEEE x ", 10)+"&amp;", 10)
+       benchUnescapeDense  = strings.Repeat("&amp;&lt; &amp; &lt;", 100)
 )
 
 func BenchmarkEscape(b *testing.B) {
@@ -151,3 +153,17 @@ func BenchmarkUnescapeNone(b *testing.B) {
                n += len(UnescapeString(s))
        }
 }
+
+func BenchmarkUnescapeSparse(b *testing.B) {
+       n := 0
+       for i := 0; i < b.N; i++ {
+               n += len(UnescapeString(benchUnescapeSparse))
+       }
+}
+
+func BenchmarkUnescapeDense(b *testing.B) {
+       n := 0
+       for i := 0; i < b.N; i++ {
+               n += len(UnescapeString(benchUnescapeDense))
+       }
+}
index c89d22a6f90af3c2641aace53a30b199894228ed..d7c62fa3993b042fcc53ed7e03f1f5be5f769695 100644 (file)
@@ -78,9 +78,17 @@ func TestClone(t *testing.T) {
        Must(t0.Parse(`{{define "lhs"}} ( {{end}}`))
        Must(t0.Parse(`{{define "rhs"}} ) {{end}}`))
 
-       // Clone t0 as t4. Redefining the "lhs" template should fail.
+       // Clone t0 as t4. Redefining the "lhs" template should not fail.
        t4 := Must(t0.Clone())
-       if _, err := t4.Parse(`{{define "lhs"}} FAIL {{end}}`); err == nil {
+       if _, err := t4.Parse(`{{define "lhs"}} OK {{end}}`); err != nil {
+               t.Errorf(`redefine "lhs": got err %v want nil`, err)
+       }
+       // Cloning t1 should fail as it has been executed.
+       if _, err := t1.Clone(); err == nil {
+               t.Error("cloning t1: got nil err want non-nil")
+       }
+       // Redefining the "lhs" template in t1 should fail as it has been executed.
+       if _, err := t1.Parse(`{{define "lhs"}} OK {{end}}`); err == nil {
                t.Error(`redefine "lhs": got nil err want non-nil`)
        }
 
index 59e794d6861f058cd6fa4a98e40c23b6c9657356..c90fc1fda5d5a876004ceaaecf1c6c85d1aa4304 100644 (file)
@@ -310,7 +310,8 @@ func (e element) String() string {
        return fmt.Sprintf("illegal element %d", int(e))
 }
 
-// attr identifies the most recent HTML attribute when inside a start tag.
+// attr identifies the current HTML attribute when inside the attribute,
+// that is, starting from stateAttrName until stateTag/stateText (exclusive).
 type attr uint8
 
 const (
index bea2d133c337a1220220e891e9e7cf6d85acab08..707394e3b02456ad10559338b55169902d4d7b25 100644 (file)
@@ -1054,7 +1054,7 @@ func TestEscapeText(t *testing.T) {
                },
                {
                        `<a href=x`,
-                       context{state: stateURL, delim: delimSpaceOrTagEnd, urlPart: urlPartPreQuery},
+                       context{state: stateURL, delim: delimSpaceOrTagEnd, urlPart: urlPartPreQuery, attr: attrURL},
                },
                {
                        `<a href=x `,
@@ -1070,7 +1070,7 @@ func TestEscapeText(t *testing.T) {
                },
                {
                        `<a href ='`,
-                       context{state: stateURL, delim: delimSingleQuote},
+                       context{state: stateURL, delim: delimSingleQuote, attr: attrURL},
                },
                {
                        `<a href=''`,
@@ -1078,7 +1078,7 @@ func TestEscapeText(t *testing.T) {
                },
                {
                        `<a href= "`,
-                       context{state: stateURL, delim: delimDoubleQuote},
+                       context{state: stateURL, delim: delimDoubleQuote, attr: attrURL},
                },
                {
                        `<a href=""`,
@@ -1090,35 +1090,35 @@ func TestEscapeText(t *testing.T) {
                },
                {
                        `<a HREF='http:`,
-                       context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery},
+                       context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery, attr: attrURL},
                },
                {
                        `<a Href='/`,
-                       context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery},
+                       context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery, attr: attrURL},
                },
                {
                        `<a href='"`,
-                       context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery},
+                       context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery, attr: attrURL},
                },
                {
                        `<a href="'`,
-                       context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery},
+                       context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrURL},
                },
                {
                        `<a href='&apos;`,
-                       context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery},
+                       context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery, attr: attrURL},
                },
                {
                        `<a href="&quot;`,
-                       context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery},
+                       context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrURL},
                },
                {
                        `<a href="&#34;`,
-                       context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery},
+                       context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrURL},
                },
                {
                        `<a href=&quot;`,
-                       context{state: stateURL, delim: delimSpaceOrTagEnd, urlPart: urlPartPreQuery},
+                       context{state: stateURL, delim: delimSpaceOrTagEnd, urlPart: urlPartPreQuery, attr: attrURL},
                },
                {
                        `<img alt="1">`,
@@ -1138,83 +1138,83 @@ func TestEscapeText(t *testing.T) {
                },
                {
                        `<a onclick="`,
-                       context{state: stateJS, delim: delimDoubleQuote},
+                       context{state: stateJS, delim: delimDoubleQuote, attr: attrScript},
                },
                {
                        `<a onclick="//foo`,
-                       context{state: stateJSLineCmt, delim: delimDoubleQuote},
+                       context{state: stateJSLineCmt, delim: delimDoubleQuote, attr: attrScript},
                },
                {
                        "<a onclick='//\n",
-                       context{state: stateJS, delim: delimSingleQuote},
+                       context{state: stateJS, delim: delimSingleQuote, attr: attrScript},
                },
                {
                        "<a onclick='//\r\n",
-                       context{state: stateJS, delim: delimSingleQuote},
+                       context{state: stateJS, delim: delimSingleQuote, attr: attrScript},
                },
                {
                        "<a onclick='//\u2028",
-                       context{state: stateJS, delim: delimSingleQuote},
+                       context{state: stateJS, delim: delimSingleQuote, attr: attrScript},
                },
                {
                        `<a onclick="/*`,
-                       context{state: stateJSBlockCmt, delim: delimDoubleQuote},
+                       context{state: stateJSBlockCmt, delim: delimDoubleQuote, attr: attrScript},
                },
                {
                        `<a onclick="/*/`,
-                       context{state: stateJSBlockCmt, delim: delimDoubleQuote},
+                       context{state: stateJSBlockCmt, delim: delimDoubleQuote, attr: attrScript},
                },
                {
                        `<a onclick="/**/`,
-                       context{state: stateJS, delim: delimDoubleQuote},
+                       context{state: stateJS, delim: delimDoubleQuote, attr: attrScript},
                },
                {
                        `<a onkeypress="&quot;`,
-                       context{state: stateJSDqStr, delim: delimDoubleQuote},
+                       context{state: stateJSDqStr, delim: delimDoubleQuote, attr: attrScript},
                },
                {
                        `<a onclick='&quot;foo&quot;`,
-                       context{state: stateJS, delim: delimSingleQuote, jsCtx: jsCtxDivOp},
+                       context{state: stateJS, delim: delimSingleQuote, jsCtx: jsCtxDivOp, attr: attrScript},
                },
                {
                        `<a onclick=&#39;foo&#39;`,
-                       context{state: stateJS, delim: delimSpaceOrTagEnd, jsCtx: jsCtxDivOp},
+                       context{state: stateJS, delim: delimSpaceOrTagEnd, jsCtx: jsCtxDivOp, attr: attrScript},
                },
                {
                        `<a onclick=&#39;foo`,
-                       context{state: stateJSSqStr, delim: delimSpaceOrTagEnd},
+                       context{state: stateJSSqStr, delim: delimSpaceOrTagEnd, attr: attrScript},
                },
                {
                        `<a onclick="&quot;foo'`,
-                       context{state: stateJSDqStr, delim: delimDoubleQuote},
+                       context{state: stateJSDqStr, delim: delimDoubleQuote, attr: attrScript},
                },
                {
                        `<a onclick="'foo&quot;`,
-                       context{state: stateJSSqStr, delim: delimDoubleQuote},
+                       context{state: stateJSSqStr, delim: delimDoubleQuote, attr: attrScript},
                },
                {
                        `<A ONCLICK="'`,
-                       context{state: stateJSSqStr, delim: delimDoubleQuote},
+                       context{state: stateJSSqStr, delim: delimDoubleQuote, attr: attrScript},
                },
                {
                        `<a onclick="/`,
-                       context{state: stateJSRegexp, delim: delimDoubleQuote},
+                       context{state: stateJSRegexp, delim: delimDoubleQuote, attr: attrScript},
                },
                {
                        `<a onclick="'foo'`,
-                       context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp},
+                       context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp, attr: attrScript},
                },
                {
                        `<a onclick="'foo\'`,
-                       context{state: stateJSSqStr, delim: delimDoubleQuote},
+                       context{state: stateJSSqStr, delim: delimDoubleQuote, attr: attrScript},
                },
                {
                        `<a onclick="'foo\'`,
-                       context{state: stateJSSqStr, delim: delimDoubleQuote},
+                       context{state: stateJSSqStr, delim: delimDoubleQuote, attr: attrScript},
                },
                {
                        `<a onclick="/foo/`,
-                       context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp},
+                       context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp, attr: attrScript},
                },
                {
                        `<script>/foo/ /=`,
@@ -1222,111 +1222,111 @@ func TestEscapeText(t *testing.T) {
                },
                {
                        `<a onclick="1 /foo`,
-                       context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp},
+                       context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp, attr: attrScript},
                },
                {
                        `<a onclick="1 /*c*/ /foo`,
-                       context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp},
+                       context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp, attr: attrScript},
                },
                {
                        `<a onclick="/foo[/]`,
-                       context{state: stateJSRegexp, delim: delimDoubleQuote},
+                       context{state: stateJSRegexp, delim: delimDoubleQuote, attr: attrScript},
                },
                {
                        `<a onclick="/foo\/`,
-                       context{state: stateJSRegexp, delim: delimDoubleQuote},
+                       context{state: stateJSRegexp, delim: delimDoubleQuote, attr: attrScript},
                },
                {
                        `<a onclick="/foo/`,
-                       context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp},
+                       context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp, attr: attrScript},
                },
                {
                        `<input checked style="`,
-                       context{state: stateCSS, delim: delimDoubleQuote},
+                       context{state: stateCSS, delim: delimDoubleQuote, attr: attrStyle},
                },
                {
                        `<a style="//`,
-                       context{state: stateCSSLineCmt, delim: delimDoubleQuote},
+                       context{state: stateCSSLineCmt, delim: delimDoubleQuote, attr: attrStyle},
                },
                {
                        `<a style="//</script>`,
-                       context{state: stateCSSLineCmt, delim: delimDoubleQuote},
+                       context{state: stateCSSLineCmt, delim: delimDoubleQuote, attr: attrStyle},
                },
                {
                        "<a style='//\n",
-                       context{state: stateCSS, delim: delimSingleQuote},
+                       context{state: stateCSS, delim: delimSingleQuote, attr: attrStyle},
                },
                {
                        "<a style='//\r",
-                       context{state: stateCSS, delim: delimSingleQuote},
+                       context{state: stateCSS, delim: delimSingleQuote, attr: attrStyle},
                },
                {
                        `<a style="/*`,
-                       context{state: stateCSSBlockCmt, delim: delimDoubleQuote},
+                       context{state: stateCSSBlockCmt, delim: delimDoubleQuote, attr: attrStyle},
                },
                {
                        `<a style="/*/`,
-                       context{state: stateCSSBlockCmt, delim: delimDoubleQuote},
+                       context{state: stateCSSBlockCmt, delim: delimDoubleQuote, attr: attrStyle},
                },
                {
                        `<a style="/**/`,
-                       context{state: stateCSS, delim: delimDoubleQuote},
+                       context{state: stateCSS, delim: delimDoubleQuote, attr: attrStyle},
                },
                {
                        `<a style="background: '`,
-                       context{state: stateCSSSqStr, delim: delimDoubleQuote},
+                       context{state: stateCSSSqStr, delim: delimDoubleQuote, attr: attrStyle},
                },
                {
                        `<a style="background: &quot;`,
-                       context{state: stateCSSDqStr, delim: delimDoubleQuote},
+                       context{state: stateCSSDqStr, delim: delimDoubleQuote, attr: attrStyle},
                },
                {
                        `<a style="background: '/foo?img=`,
-                       context{state: stateCSSSqStr, delim: delimDoubleQuote, urlPart: urlPartQueryOrFrag},
+                       context{state: stateCSSSqStr, delim: delimDoubleQuote, urlPart: urlPartQueryOrFrag, attr: attrStyle},
                },
                {
                        `<a style="background: '/`,
-                       context{state: stateCSSSqStr, delim: delimDoubleQuote, urlPart: urlPartPreQuery},
+                       context{state: stateCSSSqStr, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrStyle},
                },
                {
                        `<a style="background: url(&#x22;/`,
-                       context{state: stateCSSDqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery},
+                       context{state: stateCSSDqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrStyle},
                },
                {
                        `<a style="background: url('/`,
-                       context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery},
+                       context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrStyle},
                },
                {
                        `<a style="background: url('/)`,
-                       context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery},
+                       context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrStyle},
                },
                {
                        `<a style="background: url('/ `,
-                       context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery},
+                       context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrStyle},
                },
                {
                        `<a style="background: url(/`,
-                       context{state: stateCSSURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery},
+                       context{state: stateCSSURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrStyle},
                },
                {
                        `<a style="background: url( `,
-                       context{state: stateCSSURL, delim: delimDoubleQuote},
+                       context{state: stateCSSURL, delim: delimDoubleQuote, attr: attrStyle},
                },
                {
                        `<a style="background: url( /image?name=`,
-                       context{state: stateCSSURL, delim: delimDoubleQuote, urlPart: urlPartQueryOrFrag},
+                       context{state: stateCSSURL, delim: delimDoubleQuote, urlPart: urlPartQueryOrFrag, attr: attrStyle},
                },
                {
                        `<a style="background: url(x)`,
-                       context{state: stateCSS, delim: delimDoubleQuote},
+                       context{state: stateCSS, delim: delimDoubleQuote, attr: attrStyle},
                },
                {
                        `<a style="background: url('x'`,
-                       context{state: stateCSS, delim: delimDoubleQuote},
+                       context{state: stateCSS, delim: delimDoubleQuote, attr: attrStyle},
                },
                {
                        `<a style="background: url( x `,
-                       context{state: stateCSS, delim: delimDoubleQuote},
+                       context{state: stateCSS, delim: delimDoubleQuote, attr: attrStyle},
                },
                {
                        `<!-- foo`,
@@ -1466,7 +1466,7 @@ func TestEscapeText(t *testing.T) {
                },
                {
                        `<a svg:style='`,
-                       context{state: stateCSS, delim: delimSingleQuote},
+                       context{state: stateCSS, delim: delimSingleQuote, attr: attrStyle},
                },
                {
                        `<svg:font-face`,
@@ -1474,7 +1474,11 @@ func TestEscapeText(t *testing.T) {
                },
                {
                        `<svg:a svg:onclick="`,
-                       context{state: stateJS, delim: delimDoubleQuote},
+                       context{state: stateJS, delim: delimDoubleQuote, attr: attrScript},
+               },
+               {
+                       `<svg:a svg:onclick="x()">`,
+                       context{},
                },
        }
 
index 3ea3dca304c1b4ede52a64c9888f95e3a3249d2d..de7cdbbd91ac1d5452cbea7ef3a07797f5fbc3d0 100644 (file)
@@ -11,6 +11,7 @@ import (
        "html/template"
        "log"
        "os"
+       "strings"
 )
 
 func Example() {
@@ -32,6 +33,7 @@ func Example() {
                }
        }
        t, err := template.New("webpage").Parse(tpl)
+       check(err)
 
        data := struct {
                Title string
@@ -122,3 +124,38 @@ func Example_escape() {
        // %22Fran+%26+Freddie%27s+Diner%2232%3Ctasty%40example.com%3E
 
 }
+
+// The following example is duplicated in text/template; keep them in sync.
+
+func ExampleTemplate_block() {
+       const (
+               master  = `Names:{{block "list" .}}{{"\n"}}{{range .}}{{println "-" .}}{{end}}{{end}}`
+               overlay = `{{define "list"}} {{join . ", "}}{{end}} `
+       )
+       var (
+               funcs     = template.FuncMap{"join": strings.Join}
+               guardians = []string{"Gamora", "Groot", "Nebula", "Rocket", "Star-Lord"}
+       )
+       masterTmpl, err := template.New("master").Funcs(funcs).Parse(master)
+       if err != nil {
+               log.Fatal(err)
+       }
+       overlayTmpl, err := template.Must(masterTmpl.Clone()).Parse(overlay)
+       if err != nil {
+               log.Fatal(err)
+       }
+       if err := masterTmpl.Execute(os.Stdout, guardians); err != nil {
+               log.Fatal(err)
+       }
+       if err := overlayTmpl.Execute(os.Stdout, guardians); err != nil {
+               log.Fatal(err)
+       }
+       // Output:
+       // Names:
+       // - Gamora
+       // - Groot
+       // - Nebula
+       // - Rocket
+       // - Star-Lord
+       // Names: Gamora, Groot, Nebula, Rocket, Star-Lord
+}
index bb9140a4daf0855433ad0565cf109b70eeb0ac00..96ab268a7f44b5eed2d30ac75d8d2de12ea91144 100644 (file)
@@ -17,7 +17,7 @@ import (
 // Template is a specialized Template from "text/template" that produces a safe
 // HTML document fragment.
 type Template struct {
-       // Sticky error if escaping fails.
+       // Sticky error if escaping fails, or escapeOK if succeeded.
        escapeErr error
        // We could embed the text/template field, but it's safer not to because
        // we need to keep our version of the name space and the underlying
@@ -80,7 +80,7 @@ func (t *Template) escape() error {
        defer t.nameSpace.mu.Unlock()
        if t.escapeErr == nil {
                if t.Tree == nil {
-                       return fmt.Errorf("template: %q is an incomplete or empty template%s", t.Name(), t.text.DefinedTemplates())
+                       return fmt.Errorf("template: %q is an incomplete or empty template%s", t.Name(), t.DefinedTemplates())
                }
                if err := escapeTemplate(t, t.text.Root, t.Name()); err != nil {
                        return err
@@ -143,6 +143,13 @@ func (t *Template) lookupAndEscapeTemplate(name string) (tmpl *Template, err err
        return tmpl, err
 }
 
+// DefinedTemplates returns a string listing the defined templates,
+// prefixed by the string "; defined templates are: ". If there are none,
+// it returns the empty string. Used to generate an error message.
+func (t *Template) DefinedTemplates() string {
+       return t.text.DefinedTemplates()
+}
+
 // Parse parses a string into a template. Nested template definitions
 // will be associated with the top-level template t. Parse may be
 // called multiple times to parse definitions of templates to associate
@@ -169,6 +176,8 @@ func (t *Template) Parse(src string) (*Template, error) {
                tmpl := t.set[name]
                if tmpl == nil {
                        tmpl = t.new(name)
+               } else if tmpl.escapeErr != nil {
+                       return nil, fmt.Errorf("html/template: cannot redefine %q after it has executed", name)
                }
                // Restore our record of this text/template to its unescaped original state.
                tmpl.escapeErr = nil
@@ -228,6 +237,7 @@ func (t *Template) Clone() (*Template, error) {
                        set: make(map[string]*Template),
                },
        }
+       ret.set[ret.Name()] = ret
        for _, x := range textClone.Templates() {
                name := x.Name()
                src := t.set[name]
@@ -413,3 +423,10 @@ func parseGlob(t *Template, pattern string) (*Template, error) {
        }
        return parseFiles(t, filenames...)
 }
+
+// IsTrue reports whether the value is 'true', in the sense of not the zero of its type,
+// and whether the value has a meaningful truth value. This is the definition of
+// truth used by if and other such actions.
+func IsTrue(val interface{}) (truth, ok bool) {
+       return template.IsTrue(val)
+}
diff --git a/libgo/go/html/template/template_test.go b/libgo/go/html/template/template_test.go
new file mode 100644 (file)
index 0000000..6f70d67
--- /dev/null
@@ -0,0 +1,29 @@
+package template
+
+import (
+       "bytes"
+       "testing"
+)
+
+func TestTemplateClone(t *testing.T) {
+       // https://golang.org/issue/12996
+       orig := New("name")
+       clone, err := orig.Clone()
+       if err != nil {
+               t.Fatal(err)
+       }
+       if len(clone.Templates()) != len(orig.Templates()) {
+               t.Fatalf("Invalid lenth of t.Clone().Templates()")
+       }
+
+       const want = "stuff"
+       parsed := Must(clone.Parse(want))
+       var buf bytes.Buffer
+       err = parsed.Execute(&buf, nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+       if got := buf.String(); got != want {
+               t.Fatalf("got %q; want %q", got, want)
+       }
+}
index d2e028741a17dfd48d64b501fe8e93c5cdf2edfe..aefe0355af4c73c471db2eae8b2a5ca9f9fbb41d 100644 (file)
@@ -169,7 +169,7 @@ func tBeforeValue(c context, s []byte) (context, int) {
        case '"':
                delim, i = delimDoubleQuote, i+1
        }
-       c.state, c.delim, c.attr = attrStartStates[c.attr], delim, attrNone
+       c.state, c.delim = attrStartStates[c.attr], delim
        return c, i
 }
 
index 4bcb07dce221e3055553d0057cace63f3da022b2..904434f6a3d8a9830c15befc4623550c737fba3f 100644 (file)
@@ -98,7 +98,7 @@ func (c YCbCr) RGBA() (uint32, uint32, uint32, uint32) {
        //      fmt.Printf("0x%04x 0x%04x 0x%04x\n", r0, g0, b0)
        //      fmt.Printf("0x%04x 0x%04x 0x%04x\n", r1, g1, b1)
        // prints:
-       //      0x7e18 0x808e 0x7db9
+       //      0x7e18 0x808d 0x7db9
        //      0x7e7e 0x8080 0x7d7d
 
        yy1 := int32(c.Y) * 0x10100 // Convert 0x12 to 0x121200.
@@ -137,6 +137,66 @@ func yCbCrModel(c Color) Color {
        return YCbCr{y, u, v}
 }
 
+// NYCbCrA represents a non-alpha-premultiplied Y'CbCr-with-alpha color, having
+// 8 bits each for one luma, two chroma and one alpha component.
+type NYCbCrA struct {
+       YCbCr
+       A uint8
+}
+
+func (c NYCbCrA) RGBA() (uint32, uint32, uint32, uint32) {
+       // The first part of this method is the same as YCbCr.RGBA.
+       yy1 := int32(c.Y) * 0x10100 // Convert 0x12 to 0x121200.
+       cb1 := int32(c.Cb) - 128
+       cr1 := int32(c.Cr) - 128
+       r := (yy1 + 91881*cr1) >> 8
+       g := (yy1 - 22554*cb1 - 46802*cr1) >> 8
+       b := (yy1 + 116130*cb1) >> 8
+       if r < 0 {
+               r = 0
+       } else if r > 0xffff {
+               r = 0xffff
+       }
+       if g < 0 {
+               g = 0
+       } else if g > 0xffff {
+               g = 0xffff
+       }
+       if b < 0 {
+               b = 0
+       } else if b > 0xffff {
+               b = 0xffff
+       }
+
+       // The second part of this method applies the alpha.
+       a := uint32(c.A) * 0x101
+       return uint32(r) * a / 0xffff, uint32(g) * a / 0xffff, uint32(b) * a / 0xffff, a
+}
+
+// NYCbCrAModel is the Model for non-alpha-premultiplied Y'CbCr-with-alpha
+// colors.
+var NYCbCrAModel Model = ModelFunc(nYCbCrAModel)
+
+func nYCbCrAModel(c Color) Color {
+       switch c := c.(type) {
+       case NYCbCrA:
+               return c
+       case YCbCr:
+               return NYCbCrA{c, 0xff}
+       }
+       r, g, b, a := c.RGBA()
+
+       // Convert from alpha-premultiplied to non-alpha-premultiplied.
+       if a != 0 {
+               r = (r * 0xffff) / a
+               g = (g * 0xffff) / a
+               b = (b * 0xffff) / a
+       }
+
+       y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
+       return NYCbCrA{YCbCr{Y: y, Cb: u, Cr: v}, uint8(a >> 8)}
+}
+
 // RGBToCMYK converts an RGB triple to a CMYK quadruple.
 func RGBToCMYK(r, g, b uint8) (uint8, uint8, uint8, uint8) {
        rr := uint32(r)
index 5da49d379aa799d04f0ed8a1ba480f0cbab536ec..f5e7cbf3358ce609e5986d814abdbbb9b116a608 100644 (file)
@@ -67,7 +67,31 @@ func TestYCbCrToRGBConsistency(t *testing.T) {
 // TestYCbCrGray tests that YCbCr colors are a superset of Gray colors.
 func TestYCbCrGray(t *testing.T) {
        for i := 0; i < 256; i++ {
-               if err := eq(YCbCr{uint8(i), 0x80, 0x80}, Gray{uint8(i)}); err != nil {
+               c0 := YCbCr{uint8(i), 0x80, 0x80}
+               c1 := Gray{uint8(i)}
+               if err := eq(c0, c1); err != nil {
+                       t.Errorf("i=0x%02x:\n%v", i, err)
+               }
+       }
+}
+
+// TestNYCbCrAAlpha tests that NYCbCrA colors are a superset of Alpha colors.
+func TestNYCbCrAAlpha(t *testing.T) {
+       for i := 0; i < 256; i++ {
+               c0 := NYCbCrA{YCbCr{0xff, 0x80, 0x80}, uint8(i)}
+               c1 := Alpha{uint8(i)}
+               if err := eq(c0, c1); err != nil {
+                       t.Errorf("i=0x%02x:\n%v", i, err)
+               }
+       }
+}
+
+// TestNYCbCrAYCbCr tests that NYCbCrA colors are a superset of YCbCr colors.
+func TestNYCbCrAYCbCr(t *testing.T) {
+       for i := 0; i < 256; i++ {
+               c0 := NYCbCrA{YCbCr{uint8(i), 0x40, 0xc0}, 0xff}
+               c1 := YCbCr{uint8(i), 0x40, 0xc0}
+               if err := eq(c0, c1); err != nil {
                        t.Errorf("i=0x%02x:\n%v", i, err)
                }
        }
index 9419d5e72a757ac798bb51e68d23787d1acba5c9..e47c48d961e96afcb3dbb0902e36689494d9a999 100644 (file)
@@ -240,15 +240,15 @@ func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
        i1 := i0 + r.Dx()*4
        for y := r.Min.Y; y != r.Max.Y; y++ {
                for i := i0; i < i1; i += 4 {
-                       dr := uint32(dst.Pix[i+0])
-                       dg := uint32(dst.Pix[i+1])
-                       db := uint32(dst.Pix[i+2])
-                       da := uint32(dst.Pix[i+3])
-
-                       dst.Pix[i+0] = uint8((dr*a/m + sr) >> 8)
-                       dst.Pix[i+1] = uint8((dg*a/m + sg) >> 8)
-                       dst.Pix[i+2] = uint8((db*a/m + sb) >> 8)
-                       dst.Pix[i+3] = uint8((da*a/m + sa) >> 8)
+                       dr := &dst.Pix[i+0]
+                       dg := &dst.Pix[i+1]
+                       db := &dst.Pix[i+2]
+                       da := &dst.Pix[i+3]
+
+                       *dr = uint8((uint32(*dr)*a/m + sr) >> 8)
+                       *dg = uint8((uint32(*dg)*a/m + sg) >> 8)
+                       *db = uint8((uint32(*db)*a/m + sb) >> 8)
+                       *da = uint8((uint32(*da)*a/m + sa) >> 8)
                }
                i0 += dst.Stride
                i1 += dst.Stride
@@ -310,18 +310,18 @@ func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.
                        sb := uint32(spix[i+2]) * 0x101
                        sa := uint32(spix[i+3]) * 0x101
 
-                       dr := uint32(dpix[i+0])
-                       dg := uint32(dpix[i+1])
-                       db := uint32(dpix[i+2])
-                       da := uint32(dpix[i+3])
+                       dr := &dpix[i+0]
+                       dg := &dpix[i+1]
+                       db := &dpix[i+2]
+                       da := &dpix[i+3]
 
                        // The 0x101 is here for the same reason as in drawRGBA.
                        a := (m - sa) * 0x101
 
-                       dpix[i+0] = uint8((dr*a/m + sr) >> 8)
-                       dpix[i+1] = uint8((dg*a/m + sg) >> 8)
-                       dpix[i+2] = uint8((db*a/m + sb) >> 8)
-                       dpix[i+3] = uint8((da*a/m + sa) >> 8)
+                       *dr = uint8((uint32(*dr)*a/m + sr) >> 8)
+                       *dg = uint8((uint32(*dg)*a/m + sg) >> 8)
+                       *db = uint8((uint32(*db)*a/m + sb) >> 8)
+                       *da = uint8((uint32(*da)*a/m + sa) >> 8)
                }
                d0 += ddelta
                s0 += sdelta
@@ -471,18 +471,18 @@ func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask
                        }
                        ma |= ma << 8
 
-                       dr := uint32(dst.Pix[i+0])
-                       dg := uint32(dst.Pix[i+1])
-                       db := uint32(dst.Pix[i+2])
-                       da := uint32(dst.Pix[i+3])
+                       dr := &dst.Pix[i+0]
+                       dg := &dst.Pix[i+1]
+                       db := &dst.Pix[i+2]
+                       da := &dst.Pix[i+3]
 
                        // The 0x101 is here for the same reason as in drawRGBA.
                        a := (m - (sa * ma / m)) * 0x101
 
-                       dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8)
-                       dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8)
-                       dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8)
-                       dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8)
+                       *dr = uint8((uint32(*dr)*a + sr*ma) / m >> 8)
+                       *dg = uint8((uint32(*dg)*a + sg*ma) / m >> 8)
+                       *db = uint8((uint32(*db)*a + sb*ma) / m >> 8)
+                       *da = uint8((uint32(*da)*a + sa*ma) / m >> 8)
                }
                i0 += dst.Stride
                i1 += dst.Stride
index dd317901d483f7029f6d07de6ac77acb1854aa1f..1918196884df0f0eba2b7dd39a957cc9bb921f2b 100644 (file)
@@ -83,7 +83,7 @@ func (b blockWriter) Write(data []byte) (int, error) {
                total += n
                b.e.buf[0] = uint8(n)
 
-               n, b.e.err = b.e.w.Write(b.e.buf[:n+1])
+               _, b.e.err = b.e.w.Write(b.e.buf[:n+1])
                if b.e.err != nil {
                        return 0, b.e.err
                }
index db61a5c3c2ecc4c9fb742eca6165efc3dcd158eb..775ccea31dcf655fc7cb603dfed88f8e46b75c47 100644 (file)
@@ -328,11 +328,11 @@ func TestEncodeAllFramesOutOfBounds(t *testing.T) {
 
 func TestEncodeNonZeroMinPoint(t *testing.T) {
        points := []image.Point{
-               image.Point{-8, -9},
-               image.Point{-4, -4},
-               image.Point{-3, +3},
-               image.Point{+0, +0},
-               image.Point{+2, +2},
+               {-8, -9},
+               {-4, -4},
+               {-3, +3},
+               {+0, +0},
+               {+2, +2},
        }
        for _, p := range points {
                src := image.NewPaletted(image.Rectangle{Min: p, Max: p.Add(image.Point{6, 6})}, palette.Plan9)
index 20b64d78e1aab97b858e522afacb0f34b2f7c3e5..bebb9f70fa65e03dc41057bf5a66b7ff8d3bba5e 100644 (file)
@@ -148,7 +148,7 @@ func (p *RGBA) Opaque() bool {
        return true
 }
 
-// NewRGBA returns a new RGBA with the given bounds.
+// NewRGBA returns a new RGBA image with the given bounds.
 func NewRGBA(r Rectangle) *RGBA {
        w, h := r.Dx(), r.Dy()
        buf := make([]uint8, 4*w*h)
@@ -260,7 +260,7 @@ func (p *RGBA64) Opaque() bool {
        return true
 }
 
-// NewRGBA64 returns a new RGBA64 with the given bounds.
+// NewRGBA64 returns a new RGBA64 image with the given bounds.
 func NewRGBA64(r Rectangle) *RGBA64 {
        w, h := r.Dx(), r.Dy()
        pix := make([]uint8, 8*w*h)
@@ -359,7 +359,7 @@ func (p *NRGBA) Opaque() bool {
        return true
 }
 
-// NewNRGBA returns a new NRGBA with the given bounds.
+// NewNRGBA returns a new NRGBA image with the given bounds.
 func NewNRGBA(r Rectangle) *NRGBA {
        w, h := r.Dx(), r.Dy()
        pix := make([]uint8, 4*w*h)
@@ -471,7 +471,7 @@ func (p *NRGBA64) Opaque() bool {
        return true
 }
 
-// NewNRGBA64 returns a new NRGBA64 with the given bounds.
+// NewNRGBA64 returns a new NRGBA64 image with the given bounds.
 func NewNRGBA64(r Rectangle) *NRGBA64 {
        w, h := r.Dx(), r.Dy()
        pix := make([]uint8, 8*w*h)
@@ -563,7 +563,7 @@ func (p *Alpha) Opaque() bool {
        return true
 }
 
-// NewAlpha returns a new Alpha with the given bounds.
+// NewAlpha returns a new Alpha image with the given bounds.
 func NewAlpha(r Rectangle) *Alpha {
        w, h := r.Dx(), r.Dy()
        pix := make([]uint8, 1*w*h)
@@ -658,7 +658,7 @@ func (p *Alpha16) Opaque() bool {
        return true
 }
 
-// NewAlpha16 returns a new Alpha16 with the given bounds.
+// NewAlpha16 returns a new Alpha16 image with the given bounds.
 func NewAlpha16(r Rectangle) *Alpha16 {
        w, h := r.Dx(), r.Dy()
        pix := make([]uint8, 2*w*h)
@@ -737,7 +737,7 @@ func (p *Gray) Opaque() bool {
        return true
 }
 
-// NewGray returns a new Gray with the given bounds.
+// NewGray returns a new Gray image with the given bounds.
 func NewGray(r Rectangle) *Gray {
        w, h := r.Dx(), r.Dy()
        pix := make([]uint8, 1*w*h)
@@ -819,7 +819,7 @@ func (p *Gray16) Opaque() bool {
        return true
 }
 
-// NewGray16 returns a new Gray16 with the given bounds.
+// NewGray16 returns a new Gray16 image with the given bounds.
 func NewGray16(r Rectangle) *Gray16 {
        w, h := r.Dx(), r.Dy()
        pix := make([]uint8, 2*w*h)
@@ -905,7 +905,7 @@ func (p *CMYK) Opaque() bool {
        return true
 }
 
-// NewCMYK returns a new CMYK with the given bounds.
+// NewCMYK returns a new CMYK image with the given bounds.
 func NewCMYK(r Rectangle) *CMYK {
        w, h := r.Dx(), r.Dy()
        buf := make([]uint8, 4*w*h)
@@ -1014,7 +1014,8 @@ func (p *Paletted) Opaque() bool {
        return true
 }
 
-// NewPaletted returns a new Paletted with the given width, height and palette.
+// NewPaletted returns a new Paletted image with the given width, height and
+// palette.
 func NewPaletted(r Rectangle, p color.Palette) *Paletted {
        w, h := r.Dx(), r.Dy()
        pix := make([]uint8, 1*w*h)
index bbd6f753fadc4fcdcd9e54e250fbd887580ea152..9e6f985f7e2b41ce67f36ea90c6471dc3bcbecc9 100644 (file)
@@ -154,8 +154,8 @@ func (d *decoder) parseIHDR(length uint32) error {
        d.interlace = int(d.tmp[12])
        w := int32(binary.BigEndian.Uint32(d.tmp[0:4]))
        h := int32(binary.BigEndian.Uint32(d.tmp[4:8]))
-       if w < 0 || h < 0 {
-               return FormatError("negative dimension")
+       if w <= 0 || h <= 0 {
+               return FormatError("non-positive dimension")
        }
        nPixels := int64(w) * int64(h)
        if nPixels != int64(int(nPixels)) {
@@ -727,6 +727,9 @@ func (d *decoder) parseChunk() error {
                d.stage = dsSeenIEND
                return d.parseIEND(length)
        }
+       if length > 0x7fffffff {
+               return FormatError(fmt.Sprintf("Bad chunk length: %d", length))
+       }
        // Ignore this chunk (of a known length).
        var ignored [4096]byte
        for length > 0 {
index f89e7efe7fedebb97d31970e34def3d2089ac755..f058f6b2275ccb83020dfb1a8c8cc57577800f62 100644 (file)
@@ -408,6 +408,18 @@ func TestMultipletRNSChunks(t *testing.T) {
        }
 }
 
+func TestUnknownChunkLengthUnderflow(t *testing.T) {
+       data := []byte{0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x06, 0xf4, 0x7c, 0x55, 0x04, 0x1a,
+               0xd3, 0x11, 0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e, 0x00, 0x00,
+               0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf4, 0x7c, 0x55, 0x04, 0x1a,
+               0xd3}
+       _, err := Decode(bytes.NewReader(data))
+       if err == nil {
+               t.Errorf("Didn't fail reading an unknown chunk with length 0xffffffff")
+       }
+}
+
 func benchmarkDecode(b *testing.B, filename string, bytesPerPixel int) {
        b.StopTimer()
        data, err := ioutil.ReadFile(filename)
index 93c354b33b41c04eaf2b2dd45c9cbc14b4704c6e..71c0518a8180e649f7cffd23e89de65e43118b3d 100644 (file)
@@ -138,9 +138,8 @@ func (p *YCbCr) Opaque() bool {
        return true
 }
 
-// NewYCbCr returns a new YCbCr with the given bounds and subsample ratio.
-func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr {
-       w, h, cw, ch := r.Dx(), r.Dy(), 0, 0
+func yCbCrSize(r Rectangle, subsampleRatio YCbCrSubsampleRatio) (w, h, cw, ch int) {
+       w, h = r.Dx(), r.Dy()
        switch subsampleRatio {
        case YCbCrSubsampleRatio422:
                cw = (r.Max.X+1)/2 - r.Min.X/2
@@ -162,6 +161,13 @@ func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr {
                cw = w
                ch = h
        }
+       return
+}
+
+// NewYCbCr returns a new YCbCr image with the given bounds and subsample
+// ratio.
+func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr {
+       w, h, cw, ch := yCbCrSize(r, subsampleRatio)
        i0 := w*h + 0*cw*ch
        i1 := w*h + 1*cw*ch
        i2 := w*h + 2*cw*ch
@@ -176,3 +182,117 @@ func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr {
                Rect:           r,
        }
 }
+
+// NYCbCrA is an in-memory image of non-alpha-premultiplied Y'CbCr-with-alpha
+// colors. A and AStride are analogous to the Y and YStride fields of the
+// embedded YCbCr.
+type NYCbCrA struct {
+       YCbCr
+       A       []uint8
+       AStride int
+}
+
+func (p *NYCbCrA) ColorModel() color.Model {
+       return color.NYCbCrAModel
+}
+
+func (p *NYCbCrA) At(x, y int) color.Color {
+       return p.NYCbCrAAt(x, y)
+}
+
+func (p *NYCbCrA) NYCbCrAAt(x, y int) color.NYCbCrA {
+       if !(Point{X: x, Y: y}.In(p.Rect)) {
+               return color.NYCbCrA{}
+       }
+       yi := p.YOffset(x, y)
+       ci := p.COffset(x, y)
+       ai := p.AOffset(x, y)
+       return color.NYCbCrA{
+               color.YCbCr{
+                       Y:  p.Y[yi],
+                       Cb: p.Cb[ci],
+                       Cr: p.Cr[ci],
+               },
+               p.A[ai],
+       }
+}
+
+// AOffset returns the index of the first element of A that corresponds to the
+// pixel at (x, y).
+func (p *NYCbCrA) AOffset(x, y int) int {
+       return (y-p.Rect.Min.Y)*p.AStride + (x - p.Rect.Min.X)
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *NYCbCrA) SubImage(r Rectangle) Image {
+       r = r.Intersect(p.Rect)
+       // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+       // either r1 or r2 if the intersection is empty. Without explicitly checking for
+       // this, the Pix[i:] expression below can panic.
+       if r.Empty() {
+               return &NYCbCrA{
+                       YCbCr: YCbCr{
+                               SubsampleRatio: p.SubsampleRatio,
+                       },
+               }
+       }
+       yi := p.YOffset(r.Min.X, r.Min.Y)
+       ci := p.COffset(r.Min.X, r.Min.Y)
+       ai := p.AOffset(r.Min.X, r.Min.Y)
+       return &NYCbCrA{
+               YCbCr: YCbCr{
+                       Y:              p.Y[yi:],
+                       Cb:             p.Cb[ci:],
+                       Cr:             p.Cr[ci:],
+                       SubsampleRatio: p.SubsampleRatio,
+                       YStride:        p.YStride,
+                       CStride:        p.CStride,
+                       Rect:           r,
+               },
+               A:       p.A[ai:],
+               AStride: p.AStride,
+       }
+}
+
+// Opaque scans the entire image and reports whether it is fully opaque.
+func (p *NYCbCrA) Opaque() bool {
+       if p.Rect.Empty() {
+               return true
+       }
+       i0, i1 := 0, p.Rect.Dx()
+       for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+               for _, a := range p.A[i0:i1] {
+                       if a != 0xff {
+                               return false
+                       }
+               }
+               i0 += p.AStride
+               i1 += p.AStride
+       }
+       return true
+}
+
+// NewNYCbCrA returns a new NYCbCrA image with the given bounds and subsample
+// ratio.
+func NewNYCbCrA(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *NYCbCrA {
+       w, h, cw, ch := yCbCrSize(r, subsampleRatio)
+       i0 := 1*w*h + 0*cw*ch
+       i1 := 1*w*h + 1*cw*ch
+       i2 := 1*w*h + 2*cw*ch
+       i3 := 2*w*h + 2*cw*ch
+       b := make([]byte, i3)
+       return &NYCbCrA{
+               YCbCr: YCbCr{
+                       Y:              b[:i0:i0],
+                       Cb:             b[i0:i1:i1],
+                       Cr:             b[i1:i2:i2],
+                       SubsampleRatio: subsampleRatio,
+                       YStride:        w,
+                       CStride:        cw,
+                       Rect:           r,
+               },
+               A:       b[i2:],
+               AStride: w,
+       }
+}
diff --git a/libgo/go/internal/golang.org/x/net/http2/hpack/encode.go b/libgo/go/internal/golang.org/x/net/http2/hpack/encode.go
new file mode 100644 (file)
index 0000000..80d621c
--- /dev/null
@@ -0,0 +1,251 @@
+// 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 hpack
+
+import (
+       "io"
+)
+
+const (
+       uint32Max              = ^uint32(0)
+       initialHeaderTableSize = 4096
+)
+
+type Encoder struct {
+       dynTab dynamicTable
+       // minSize is the minimum table size set by
+       // SetMaxDynamicTableSize after the previous Header Table Size
+       // Update.
+       minSize uint32
+       // maxSizeLimit is the maximum table size this encoder
+       // supports. This will protect the encoder from too large
+       // size.
+       maxSizeLimit uint32
+       // tableSizeUpdate indicates whether "Header Table Size
+       // Update" is required.
+       tableSizeUpdate bool
+       w               io.Writer
+       buf             []byte
+}
+
+// NewEncoder returns a new Encoder which performs HPACK encoding. An
+// encoded data is written to w.
+func NewEncoder(w io.Writer) *Encoder {
+       e := &Encoder{
+               minSize:         uint32Max,
+               maxSizeLimit:    initialHeaderTableSize,
+               tableSizeUpdate: false,
+               w:               w,
+       }
+       e.dynTab.setMaxSize(initialHeaderTableSize)
+       return e
+}
+
+// WriteField encodes f into a single Write to e's underlying Writer.
+// This function may also produce bytes for "Header Table Size Update"
+// if necessary.  If produced, it is done before encoding f.
+func (e *Encoder) WriteField(f HeaderField) error {
+       e.buf = e.buf[:0]
+
+       if e.tableSizeUpdate {
+               e.tableSizeUpdate = false
+               if e.minSize < e.dynTab.maxSize {
+                       e.buf = appendTableSize(e.buf, e.minSize)
+               }
+               e.minSize = uint32Max
+               e.buf = appendTableSize(e.buf, e.dynTab.maxSize)
+       }
+
+       idx, nameValueMatch := e.searchTable(f)
+       if nameValueMatch {
+               e.buf = appendIndexed(e.buf, idx)
+       } else {
+               indexing := e.shouldIndex(f)
+               if indexing {
+                       e.dynTab.add(f)
+               }
+
+               if idx == 0 {
+                       e.buf = appendNewName(e.buf, f, indexing)
+               } else {
+                       e.buf = appendIndexedName(e.buf, f, idx, indexing)
+               }
+       }
+       n, err := e.w.Write(e.buf)
+       if err == nil && n != len(e.buf) {
+               err = io.ErrShortWrite
+       }
+       return err
+}
+
+// searchTable searches f in both stable and dynamic header tables.
+// The static header table is searched first. Only when there is no
+// exact match for both name and value, the dynamic header table is
+// then searched. If there is no match, i is 0. If both name and value
+// match, i is the matched index and nameValueMatch becomes true. If
+// only name matches, i points to that index and nameValueMatch
+// becomes false.
+func (e *Encoder) searchTable(f HeaderField) (i uint64, nameValueMatch bool) {
+       for idx, hf := range staticTable {
+               if !constantTimeStringCompare(hf.Name, f.Name) {
+                       continue
+               }
+               if i == 0 {
+                       i = uint64(idx + 1)
+               }
+               if f.Sensitive {
+                       continue
+               }
+               if !constantTimeStringCompare(hf.Value, f.Value) {
+                       continue
+               }
+               i = uint64(idx + 1)
+               nameValueMatch = true
+               return
+       }
+
+       j, nameValueMatch := e.dynTab.search(f)
+       if nameValueMatch || (i == 0 && j != 0) {
+               i = j + uint64(len(staticTable))
+       }
+       return
+}
+
+// SetMaxDynamicTableSize changes the dynamic header table size to v.
+// The actual size is bounded by the value passed to
+// SetMaxDynamicTableSizeLimit.
+func (e *Encoder) SetMaxDynamicTableSize(v uint32) {
+       if v > e.maxSizeLimit {
+               v = e.maxSizeLimit
+       }
+       if v < e.minSize {
+               e.minSize = v
+       }
+       e.tableSizeUpdate = true
+       e.dynTab.setMaxSize(v)
+}
+
+// SetMaxDynamicTableSizeLimit changes the maximum value that can be
+// specified in SetMaxDynamicTableSize to v. By default, it is set to
+// 4096, which is the same size of the default dynamic header table
+// size described in HPACK specification. If the current maximum
+// dynamic header table size is strictly greater than v, "Header Table
+// Size Update" will be done in the next WriteField call and the
+// maximum dynamic header table size is truncated to v.
+func (e *Encoder) SetMaxDynamicTableSizeLimit(v uint32) {
+       e.maxSizeLimit = v
+       if e.dynTab.maxSize > v {
+               e.tableSizeUpdate = true
+               e.dynTab.setMaxSize(v)
+       }
+}
+
+// shouldIndex reports whether f should be indexed.
+func (e *Encoder) shouldIndex(f HeaderField) bool {
+       return !f.Sensitive && f.size() <= e.dynTab.maxSize
+}
+
+// appendIndexed appends index i, as encoded in "Indexed Header Field"
+// representation, to dst and returns the extended buffer.
+func appendIndexed(dst []byte, i uint64) []byte {
+       first := len(dst)
+       dst = appendVarInt(dst, 7, i)
+       dst[first] |= 0x80
+       return dst
+}
+
+// appendNewName appends f, as encoded in one of "Literal Header field
+// - New Name" representation variants, to dst and returns the
+// extended buffer.
+//
+// If f.Sensitive is true, "Never Indexed" representation is used. If
+// f.Sensitive is false and indexing is true, "Inremental Indexing"
+// representation is used.
+func appendNewName(dst []byte, f HeaderField, indexing bool) []byte {
+       dst = append(dst, encodeTypeByte(indexing, f.Sensitive))
+       dst = appendHpackString(dst, f.Name)
+       return appendHpackString(dst, f.Value)
+}
+
+// appendIndexedName appends f and index i referring indexed name
+// entry, as encoded in one of "Literal Header field - Indexed Name"
+// representation variants, to dst and returns the extended buffer.
+//
+// If f.Sensitive is true, "Never Indexed" representation is used. If
+// f.Sensitive is false and indexing is true, "Incremental Indexing"
+// representation is used.
+func appendIndexedName(dst []byte, f HeaderField, i uint64, indexing bool) []byte {
+       first := len(dst)
+       var n byte
+       if indexing {
+               n = 6
+       } else {
+               n = 4
+       }
+       dst = appendVarInt(dst, n, i)
+       dst[first] |= encodeTypeByte(indexing, f.Sensitive)
+       return appendHpackString(dst, f.Value)
+}
+
+// appendTableSize appends v, as encoded in "Header Table Size Update"
+// representation, to dst and returns the extended buffer.
+func appendTableSize(dst []byte, v uint32) []byte {
+       first := len(dst)
+       dst = appendVarInt(dst, 5, uint64(v))
+       dst[first] |= 0x20
+       return dst
+}
+
+// appendVarInt appends i, as encoded in variable integer form using n
+// bit prefix, to dst and returns the extended buffer.
+//
+// See
+// http://http2.github.io/http2-spec/compression.html#integer.representation
+func appendVarInt(dst []byte, n byte, i uint64) []byte {
+       k := uint64((1 << n) - 1)
+       if i < k {
+               return append(dst, byte(i))
+       }
+       dst = append(dst, byte(k))
+       i -= k
+       for ; i >= 128; i >>= 7 {
+               dst = append(dst, byte(0x80|(i&0x7f)))
+       }
+       return append(dst, byte(i))
+}
+
+// appendHpackString appends s, as encoded in "String Literal"
+// representation, to dst and returns the the extended buffer.
+//
+// s will be encoded in Huffman codes only when it produces strictly
+// shorter byte string.
+func appendHpackString(dst []byte, s string) []byte {
+       huffmanLength := HuffmanEncodeLength(s)
+       if huffmanLength < uint64(len(s)) {
+               first := len(dst)
+               dst = appendVarInt(dst, 7, huffmanLength)
+               dst = AppendHuffmanString(dst, s)
+               dst[first] |= 0x80
+       } else {
+               dst = appendVarInt(dst, 7, uint64(len(s)))
+               dst = append(dst, s...)
+       }
+       return dst
+}
+
+// encodeTypeByte returns type byte. If sensitive is true, type byte
+// for "Never Indexed" representation is returned. If sensitive is
+// false and indexing is true, type byte for "Incremental Indexing"
+// representation is returned. Otherwise, type byte for "Without
+// Indexing" is returned.
+func encodeTypeByte(indexing, sensitive bool) byte {
+       if sensitive {
+               return 0x10
+       }
+       if indexing {
+               return 0x40
+       }
+       return 0
+}
diff --git a/libgo/go/internal/golang.org/x/net/http2/hpack/encode_test.go b/libgo/go/internal/golang.org/x/net/http2/hpack/encode_test.go
new file mode 100644 (file)
index 0000000..92286f3
--- /dev/null
@@ -0,0 +1,330 @@
+// 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 hpack
+
+import (
+       "bytes"
+       "encoding/hex"
+       "reflect"
+       "strings"
+       "testing"
+)
+
+func TestEncoderTableSizeUpdate(t *testing.T) {
+       tests := []struct {
+               size1, size2 uint32
+               wantHex      string
+       }{
+               // Should emit 2 table size updates (2048 and 4096)
+               {2048, 4096, "3fe10f 3fe11f 82"},
+
+               // Should emit 1 table size update (2048)
+               {16384, 2048, "3fe10f 82"},
+       }
+       for _, tt := range tests {
+               var buf bytes.Buffer
+               e := NewEncoder(&buf)
+               e.SetMaxDynamicTableSize(tt.size1)
+               e.SetMaxDynamicTableSize(tt.size2)
+               if err := e.WriteField(pair(":method", "GET")); err != nil {
+                       t.Fatal(err)
+               }
+               want := removeSpace(tt.wantHex)
+               if got := hex.EncodeToString(buf.Bytes()); got != want {
+                       t.Errorf("e.SetDynamicTableSize %v, %v = %q; want %q", tt.size1, tt.size2, got, want)
+               }
+       }
+}
+
+func TestEncoderWriteField(t *testing.T) {
+       var buf bytes.Buffer
+       e := NewEncoder(&buf)
+       var got []HeaderField
+       d := NewDecoder(4<<10, func(f HeaderField) {
+               got = append(got, f)
+       })
+
+       tests := []struct {
+               hdrs []HeaderField
+       }{
+               {[]HeaderField{
+                       pair(":method", "GET"),
+                       pair(":scheme", "http"),
+                       pair(":path", "/"),
+                       pair(":authority", "www.example.com"),
+               }},
+               {[]HeaderField{
+                       pair(":method", "GET"),
+                       pair(":scheme", "http"),
+                       pair(":path", "/"),
+                       pair(":authority", "www.example.com"),
+                       pair("cache-control", "no-cache"),
+               }},
+               {[]HeaderField{
+                       pair(":method", "GET"),
+                       pair(":scheme", "https"),
+                       pair(":path", "/index.html"),
+                       pair(":authority", "www.example.com"),
+                       pair("custom-key", "custom-value"),
+               }},
+       }
+       for i, tt := range tests {
+               buf.Reset()
+               got = got[:0]
+               for _, hf := range tt.hdrs {
+                       if err := e.WriteField(hf); err != nil {
+                               t.Fatal(err)
+                       }
+               }
+               _, err := d.Write(buf.Bytes())
+               if err != nil {
+                       t.Errorf("%d. Decoder Write = %v", i, err)
+               }
+               if !reflect.DeepEqual(got, tt.hdrs) {
+                       t.Errorf("%d. Decoded %+v; want %+v", i, got, tt.hdrs)
+               }
+       }
+}
+
+func TestEncoderSearchTable(t *testing.T) {
+       e := NewEncoder(nil)
+
+       e.dynTab.add(pair("foo", "bar"))
+       e.dynTab.add(pair("blake", "miz"))
+       e.dynTab.add(pair(":method", "GET"))
+
+       tests := []struct {
+               hf        HeaderField
+               wantI     uint64
+               wantMatch bool
+       }{
+               // Name and Value match
+               {pair("foo", "bar"), uint64(len(staticTable) + 3), true},
+               {pair("blake", "miz"), uint64(len(staticTable) + 2), true},
+               {pair(":method", "GET"), 2, true},
+
+               // Only name match because Sensitive == true
+               {HeaderField{":method", "GET", true}, 2, false},
+
+               // Only Name matches
+               {pair("foo", "..."), uint64(len(staticTable) + 3), false},
+               {pair("blake", "..."), uint64(len(staticTable) + 2), false},
+               {pair(":method", "..."), 2, false},
+
+               // None match
+               {pair("foo-", "bar"), 0, false},
+       }
+       for _, tt := range tests {
+               if gotI, gotMatch := e.searchTable(tt.hf); gotI != tt.wantI || gotMatch != tt.wantMatch {
+                       t.Errorf("d.search(%+v) = %v, %v; want %v, %v", tt.hf, gotI, gotMatch, tt.wantI, tt.wantMatch)
+               }
+       }
+}
+
+func TestAppendVarInt(t *testing.T) {
+       tests := []struct {
+               n    byte
+               i    uint64
+               want []byte
+       }{
+               // Fits in a byte:
+               {1, 0, []byte{0}},
+               {2, 2, []byte{2}},
+               {3, 6, []byte{6}},
+               {4, 14, []byte{14}},
+               {5, 30, []byte{30}},
+               {6, 62, []byte{62}},
+               {7, 126, []byte{126}},
+               {8, 254, []byte{254}},
+
+               // Multiple bytes:
+               {5, 1337, []byte{31, 154, 10}},
+       }
+       for _, tt := range tests {
+               got := appendVarInt(nil, tt.n, tt.i)
+               if !bytes.Equal(got, tt.want) {
+                       t.Errorf("appendVarInt(nil, %v, %v) = %v; want %v", tt.n, tt.i, got, tt.want)
+               }
+       }
+}
+
+func TestAppendHpackString(t *testing.T) {
+       tests := []struct {
+               s, wantHex string
+       }{
+               // Huffman encoded
+               {"www.example.com", "8c f1e3 c2e5 f23a 6ba0 ab90 f4ff"},
+
+               // Not Huffman encoded
+               {"a", "01 61"},
+
+               // zero length
+               {"", "00"},
+       }
+       for _, tt := range tests {
+               want := removeSpace(tt.wantHex)
+               buf := appendHpackString(nil, tt.s)
+               if got := hex.EncodeToString(buf); want != got {
+                       t.Errorf("appendHpackString(nil, %q) = %q; want %q", tt.s, got, want)
+               }
+       }
+}
+
+func TestAppendIndexed(t *testing.T) {
+       tests := []struct {
+               i       uint64
+               wantHex string
+       }{
+               // 1 byte
+               {1, "81"},
+               {126, "fe"},
+
+               // 2 bytes
+               {127, "ff00"},
+               {128, "ff01"},
+       }
+       for _, tt := range tests {
+               want := removeSpace(tt.wantHex)
+               buf := appendIndexed(nil, tt.i)
+               if got := hex.EncodeToString(buf); want != got {
+                       t.Errorf("appendIndex(nil, %v) = %q; want %q", tt.i, got, want)
+               }
+       }
+}
+
+func TestAppendNewName(t *testing.T) {
+       tests := []struct {
+               f        HeaderField
+               indexing bool
+               wantHex  string
+       }{
+               // Incremental indexing
+               {HeaderField{"custom-key", "custom-value", false}, true, "40 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"},
+
+               // Without indexing
+               {HeaderField{"custom-key", "custom-value", false}, false, "00 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"},
+
+               // Never indexed
+               {HeaderField{"custom-key", "custom-value", true}, true, "10 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"},
+               {HeaderField{"custom-key", "custom-value", true}, false, "10 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"},
+       }
+       for _, tt := range tests {
+               want := removeSpace(tt.wantHex)
+               buf := appendNewName(nil, tt.f, tt.indexing)
+               if got := hex.EncodeToString(buf); want != got {
+                       t.Errorf("appendNewName(nil, %+v, %v) = %q; want %q", tt.f, tt.indexing, got, want)
+               }
+       }
+}
+
+func TestAppendIndexedName(t *testing.T) {
+       tests := []struct {
+               f        HeaderField
+               i        uint64
+               indexing bool
+               wantHex  string
+       }{
+               // Incremental indexing
+               {HeaderField{":status", "302", false}, 8, true, "48 82 6402"},
+
+               // Without indexing
+               {HeaderField{":status", "302", false}, 8, false, "08 82 6402"},
+
+               // Never indexed
+               {HeaderField{":status", "302", true}, 8, true, "18 82 6402"},
+               {HeaderField{":status", "302", true}, 8, false, "18 82 6402"},
+       }
+       for _, tt := range tests {
+               want := removeSpace(tt.wantHex)
+               buf := appendIndexedName(nil, tt.f, tt.i, tt.indexing)
+               if got := hex.EncodeToString(buf); want != got {
+                       t.Errorf("appendIndexedName(nil, %+v, %v) = %q; want %q", tt.f, tt.indexing, got, want)
+               }
+       }
+}
+
+func TestAppendTableSize(t *testing.T) {
+       tests := []struct {
+               i       uint32
+               wantHex string
+       }{
+               // Fits into 1 byte
+               {30, "3e"},
+
+               // Extra byte
+               {31, "3f00"},
+               {32, "3f01"},
+       }
+       for _, tt := range tests {
+               want := removeSpace(tt.wantHex)
+               buf := appendTableSize(nil, tt.i)
+               if got := hex.EncodeToString(buf); want != got {
+                       t.Errorf("appendTableSize(nil, %v) = %q; want %q", tt.i, got, want)
+               }
+       }
+}
+
+func TestEncoderSetMaxDynamicTableSize(t *testing.T) {
+       var buf bytes.Buffer
+       e := NewEncoder(&buf)
+       tests := []struct {
+               v           uint32
+               wantUpdate  bool
+               wantMinSize uint32
+               wantMaxSize uint32
+       }{
+               // Set new table size to 2048
+               {2048, true, 2048, 2048},
+
+               // Set new table size to 16384, but still limited to
+               // 4096
+               {16384, true, 2048, 4096},
+       }
+       for _, tt := range tests {
+               e.SetMaxDynamicTableSize(tt.v)
+               if got := e.tableSizeUpdate; tt.wantUpdate != got {
+                       t.Errorf("e.tableSizeUpdate = %v; want %v", got, tt.wantUpdate)
+               }
+               if got := e.minSize; tt.wantMinSize != got {
+                       t.Errorf("e.minSize = %v; want %v", got, tt.wantMinSize)
+               }
+               if got := e.dynTab.maxSize; tt.wantMaxSize != got {
+                       t.Errorf("e.maxSize = %v; want %v", got, tt.wantMaxSize)
+               }
+       }
+}
+
+func TestEncoderSetMaxDynamicTableSizeLimit(t *testing.T) {
+       e := NewEncoder(nil)
+       // 4095 < initialHeaderTableSize means maxSize is truncated to
+       // 4095.
+       e.SetMaxDynamicTableSizeLimit(4095)
+       if got, want := e.dynTab.maxSize, uint32(4095); got != want {
+               t.Errorf("e.dynTab.maxSize = %v; want %v", got, want)
+       }
+       if got, want := e.maxSizeLimit, uint32(4095); got != want {
+               t.Errorf("e.maxSizeLimit = %v; want %v", got, want)
+       }
+       if got, want := e.tableSizeUpdate, true; got != want {
+               t.Errorf("e.tableSizeUpdate = %v; want %v", got, want)
+       }
+       // maxSize will be truncated to maxSizeLimit
+       e.SetMaxDynamicTableSize(16384)
+       if got, want := e.dynTab.maxSize, uint32(4095); got != want {
+               t.Errorf("e.dynTab.maxSize = %v; want %v", got, want)
+       }
+       // 8192 > current maxSizeLimit, so maxSize does not change.
+       e.SetMaxDynamicTableSizeLimit(8192)
+       if got, want := e.dynTab.maxSize, uint32(4095); got != want {
+               t.Errorf("e.dynTab.maxSize = %v; want %v", got, want)
+       }
+       if got, want := e.maxSizeLimit, uint32(8192); got != want {
+               t.Errorf("e.maxSizeLimit = %v; want %v", got, want)
+       }
+}
+
+func removeSpace(s string) string {
+       return strings.Replace(s, " ", "", -1)
+}
diff --git a/libgo/go/internal/golang.org/x/net/http2/hpack/hpack.go b/libgo/go/internal/golang.org/x/net/http2/hpack/hpack.go
new file mode 100644 (file)
index 0000000..2ea4949
--- /dev/null
@@ -0,0 +1,533 @@
+// 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 hpack implements HPACK, a compression format for
+// efficiently representing HTTP header fields in the context of HTTP/2.
+//
+// See http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09
+package hpack
+
+import (
+       "bytes"
+       "errors"
+       "fmt"
+)
+
+// A DecodingError is something the spec defines as a decoding error.
+type DecodingError struct {
+       Err error
+}
+
+func (de DecodingError) Error() string {
+       return fmt.Sprintf("decoding error: %v", de.Err)
+}
+
+// An InvalidIndexError is returned when an encoder references a table
+// entry before the static table or after the end of the dynamic table.
+type InvalidIndexError int
+
+func (e InvalidIndexError) Error() string {
+       return fmt.Sprintf("invalid indexed representation index %d", int(e))
+}
+
+// A HeaderField is a name-value pair. Both the name and value are
+// treated as opaque sequences of octets.
+type HeaderField struct {
+       Name, Value string
+
+       // Sensitive means that this header field should never be
+       // indexed.
+       Sensitive bool
+}
+
+func (hf HeaderField) String() string {
+       var suffix string
+       if hf.Sensitive {
+               suffix = " (sensitive)"
+       }
+       return fmt.Sprintf("header field %q = %q%s", hf.Name, hf.Value, suffix)
+}
+
+func (hf *HeaderField) size() uint32 {
+       // http://http2.github.io/http2-spec/compression.html#rfc.section.4.1
+       // "The size of the dynamic table is the sum of the size of
+       // its entries.  The size of an entry is the sum of its name's
+       // length in octets (as defined in Section 5.2), its value's
+       // length in octets (see Section 5.2), plus 32.  The size of
+       // an entry is calculated using the length of the name and
+       // value without any Huffman encoding applied."
+
+       // This can overflow if somebody makes a large HeaderField
+       // Name and/or Value by hand, but we don't care, because that
+       // won't happen on the wire because the encoding doesn't allow
+       // it.
+       return uint32(len(hf.Name) + len(hf.Value) + 32)
+}
+
+// A Decoder is the decoding context for incremental processing of
+// header blocks.
+type Decoder struct {
+       dynTab dynamicTable
+       emit   func(f HeaderField)
+
+       emitEnabled bool // whether calls to emit are enabled
+       maxStrLen   int  // 0 means unlimited
+
+       // buf is the unparsed buffer. It's only written to
+       // saveBuf if it was truncated in the middle of a header
+       // block. Because it's usually not owned, we can only
+       // process it under Write.
+       buf []byte // not owned; only valid during Write
+
+       // saveBuf is previous data passed to Write which we weren't able
+       // to fully parse before. Unlike buf, we own this data.
+       saveBuf bytes.Buffer
+}
+
+// NewDecoder returns a new decoder with the provided maximum dynamic
+// table size. The emitFunc will be called for each valid field
+// parsed, in the same goroutine as calls to Write, before Write returns.
+func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decoder {
+       d := &Decoder{
+               emit:        emitFunc,
+               emitEnabled: true,
+       }
+       d.dynTab.allowedMaxSize = maxDynamicTableSize
+       d.dynTab.setMaxSize(maxDynamicTableSize)
+       return d
+}
+
+// ErrStringLength is returned by Decoder.Write when the max string length
+// (as configured by Decoder.SetMaxStringLength) would be violated.
+var ErrStringLength = errors.New("hpack: string too long")
+
+// SetMaxStringLength sets the maximum size of a HeaderField name or
+// value string. If a string exceeds this length (even after any
+// decompression), Write will return ErrStringLength.
+// A value of 0 means unlimited and is the default from NewDecoder.
+func (d *Decoder) SetMaxStringLength(n int) {
+       d.maxStrLen = n
+}
+
+// SetEmitFunc changes the callback used when new header fields
+// are decoded.
+// It must be non-nil. It does not affect EmitEnabled.
+func (d *Decoder) SetEmitFunc(emitFunc func(f HeaderField)) {
+       d.emit = emitFunc
+}
+
+// SetEmitEnabled controls whether the emitFunc provided to NewDecoder
+// should be called. The default is true.
+//
+// This facility exists to let servers enforce MAX_HEADER_LIST_SIZE
+// while still decoding and keeping in-sync with decoder state, but
+// without doing unnecessary decompression or generating unnecessary
+// garbage for header fields past the limit.
+func (d *Decoder) SetEmitEnabled(v bool) { d.emitEnabled = v }
+
+// EmitEnabled reports whether calls to the emitFunc provided to NewDecoder
+// are currently enabled. The default is true.
+func (d *Decoder) EmitEnabled() bool { return d.emitEnabled }
+
+// TODO: add method *Decoder.Reset(maxSize, emitFunc) to let callers re-use Decoders and their
+// underlying buffers for garbage reasons.
+
+func (d *Decoder) SetMaxDynamicTableSize(v uint32) {
+       d.dynTab.setMaxSize(v)
+}
+
+// SetAllowedMaxDynamicTableSize sets the upper bound that the encoded
+// stream (via dynamic table size updates) may set the maximum size
+// to.
+func (d *Decoder) SetAllowedMaxDynamicTableSize(v uint32) {
+       d.dynTab.allowedMaxSize = v
+}
+
+type dynamicTable struct {
+       // ents is the FIFO described at
+       // http://http2.github.io/http2-spec/compression.html#rfc.section.2.3.2
+       // The newest (low index) is append at the end, and items are
+       // evicted from the front.
+       ents           []HeaderField
+       size           uint32
+       maxSize        uint32 // current maxSize
+       allowedMaxSize uint32 // maxSize may go up to this, inclusive
+}
+
+func (dt *dynamicTable) setMaxSize(v uint32) {
+       dt.maxSize = v
+       dt.evict()
+}
+
+// TODO: change dynamicTable to be a struct with a slice and a size int field,
+// per http://http2.github.io/http2-spec/compression.html#rfc.section.4.1:
+//
+//
+// Then make add increment the size. maybe the max size should move from Decoder to
+// dynamicTable and add should return an ok bool if there was enough space.
+//
+// Later we'll need a remove operation on dynamicTable.
+
+func (dt *dynamicTable) add(f HeaderField) {
+       dt.ents = append(dt.ents, f)
+       dt.size += f.size()
+       dt.evict()
+}
+
+// If we're too big, evict old stuff (front of the slice)
+func (dt *dynamicTable) evict() {
+       base := dt.ents // keep base pointer of slice
+       for dt.size > dt.maxSize {
+               dt.size -= dt.ents[0].size()
+               dt.ents = dt.ents[1:]
+       }
+
+       // Shift slice contents down if we evicted things.
+       if len(dt.ents) != len(base) {
+               copy(base, dt.ents)
+               dt.ents = base[:len(dt.ents)]
+       }
+}
+
+// constantTimeStringCompare compares string a and b in a constant
+// time manner.
+func constantTimeStringCompare(a, b string) bool {
+       if len(a) != len(b) {
+               return false
+       }
+
+       c := byte(0)
+
+       for i := 0; i < len(a); i++ {
+               c |= a[i] ^ b[i]
+       }
+
+       return c == 0
+}
+
+// Search searches f in the table. The return value i is 0 if there is
+// no name match. If there is name match or name/value match, i is the
+// index of that entry (1-based). If both name and value match,
+// nameValueMatch becomes true.
+func (dt *dynamicTable) search(f HeaderField) (i uint64, nameValueMatch bool) {
+       l := len(dt.ents)
+       for j := l - 1; j >= 0; j-- {
+               ent := dt.ents[j]
+               if !constantTimeStringCompare(ent.Name, f.Name) {
+                       continue
+               }
+               if i == 0 {
+                       i = uint64(l - j)
+               }
+               if f.Sensitive {
+                       continue
+               }
+               if !constantTimeStringCompare(ent.Value, f.Value) {
+                       continue
+               }
+               i = uint64(l - j)
+               nameValueMatch = true
+               return
+       }
+       return
+}
+
+func (d *Decoder) maxTableIndex() int {
+       return len(d.dynTab.ents) + len(staticTable)
+}
+
+func (d *Decoder) at(i uint64) (hf HeaderField, ok bool) {
+       if i < 1 {
+               return
+       }
+       if i > uint64(d.maxTableIndex()) {
+               return
+       }
+       if i <= uint64(len(staticTable)) {
+               return staticTable[i-1], true
+       }
+       dents := d.dynTab.ents
+       return dents[len(dents)-(int(i)-len(staticTable))], true
+}
+
+// Decode decodes an entire block.
+//
+// TODO: remove this method and make it incremental later? This is
+// easier for debugging now.
+func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error) {
+       var hf []HeaderField
+       saveFunc := d.emit
+       defer func() { d.emit = saveFunc }()
+       d.emit = func(f HeaderField) { hf = append(hf, f) }
+       if _, err := d.Write(p); err != nil {
+               return nil, err
+       }
+       if err := d.Close(); err != nil {
+               return nil, err
+       }
+       return hf, nil
+}
+
+func (d *Decoder) Close() error {
+       if d.saveBuf.Len() > 0 {
+               d.saveBuf.Reset()
+               return DecodingError{errors.New("truncated headers")}
+       }
+       return nil
+}
+
+func (d *Decoder) Write(p []byte) (n int, err error) {
+       if len(p) == 0 {
+               // Prevent state machine CPU attacks (making us redo
+               // work up to the point of finding out we don't have
+               // enough data)
+               return
+       }
+       // Only copy the data if we have to. Optimistically assume
+       // that p will contain a complete header block.
+       if d.saveBuf.Len() == 0 {
+               d.buf = p
+       } else {
+               d.saveBuf.Write(p)
+               d.buf = d.saveBuf.Bytes()
+               d.saveBuf.Reset()
+       }
+
+       for len(d.buf) > 0 {
+               err = d.parseHeaderFieldRepr()
+               if err == errNeedMore {
+                       // Extra paranoia, making sure saveBuf won't
+                       // get too large.  All the varint and string
+                       // reading code earlier should already catch
+                       // overlong things and return ErrStringLength,
+                       // but keep this as a last resort.
+                       const varIntOverhead = 8 // conservative
+                       if d.maxStrLen != 0 && int64(len(d.buf)) > 2*(int64(d.maxStrLen)+varIntOverhead) {
+                               return 0, ErrStringLength
+                       }
+                       d.saveBuf.Write(d.buf)
+                       return len(p), nil
+               }
+               if err != nil {
+                       break
+               }
+       }
+       return len(p), err
+}
+
+// errNeedMore is an internal sentinel error value that means the
+// buffer is truncated and we need to read more data before we can
+// continue parsing.
+var errNeedMore = errors.New("need more data")
+
+type indexType int
+
+const (
+       indexedTrue indexType = iota
+       indexedFalse
+       indexedNever
+)
+
+func (v indexType) indexed() bool   { return v == indexedTrue }
+func (v indexType) sensitive() bool { return v == indexedNever }
+
+// returns errNeedMore if there isn't enough data available.
+// any other error is fatal.
+// consumes d.buf iff it returns nil.
+// precondition: must be called with len(d.buf) > 0
+func (d *Decoder) parseHeaderFieldRepr() error {
+       b := d.buf[0]
+       switch {
+       case b&128 != 0:
+               // Indexed representation.
+               // High bit set?
+               // http://http2.github.io/http2-spec/compression.html#rfc.section.6.1
+               return d.parseFieldIndexed()
+       case b&192 == 64:
+               // 6.2.1 Literal Header Field with Incremental Indexing
+               // 0b10xxxxxx: top two bits are 10
+               // http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.1
+               return d.parseFieldLiteral(6, indexedTrue)
+       case b&240 == 0:
+               // 6.2.2 Literal Header Field without Indexing
+               // 0b0000xxxx: top four bits are 0000
+               // http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.2
+               return d.parseFieldLiteral(4, indexedFalse)
+       case b&240 == 16:
+               // 6.2.3 Literal Header Field never Indexed
+               // 0b0001xxxx: top four bits are 0001
+               // http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.3
+               return d.parseFieldLiteral(4, indexedNever)
+       case b&224 == 32:
+               // 6.3 Dynamic Table Size Update
+               // Top three bits are '001'.
+               // http://http2.github.io/http2-spec/compression.html#rfc.section.6.3
+               return d.parseDynamicTableSizeUpdate()
+       }
+
+       return DecodingError{errors.New("invalid encoding")}
+}
+
+// (same invariants and behavior as parseHeaderFieldRepr)
+func (d *Decoder) parseFieldIndexed() error {
+       buf := d.buf
+       idx, buf, err := readVarInt(7, buf)
+       if err != nil {
+               return err
+       }
+       hf, ok := d.at(idx)
+       if !ok {
+               return DecodingError{InvalidIndexError(idx)}
+       }
+       d.buf = buf
+       return d.callEmit(HeaderField{Name: hf.Name, Value: hf.Value})
+}
+
+// (same invariants and behavior as parseHeaderFieldRepr)
+func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error {
+       buf := d.buf
+       nameIdx, buf, err := readVarInt(n, buf)
+       if err != nil {
+               return err
+       }
+
+       var hf HeaderField
+       wantStr := d.emitEnabled || it.indexed()
+       if nameIdx > 0 {
+               ihf, ok := d.at(nameIdx)
+               if !ok {
+                       return DecodingError{InvalidIndexError(nameIdx)}
+               }
+               hf.Name = ihf.Name
+       } else {
+               hf.Name, buf, err = d.readString(buf, wantStr)
+               if err != nil {
+                       return err
+               }
+       }
+       hf.Value, buf, err = d.readString(buf, wantStr)
+       if err != nil {
+               return err
+       }
+       d.buf = buf
+       if it.indexed() {
+               d.dynTab.add(hf)
+       }
+       hf.Sensitive = it.sensitive()
+       return d.callEmit(hf)
+}
+
+func (d *Decoder) callEmit(hf HeaderField) error {
+       if d.maxStrLen != 0 {
+               if len(hf.Name) > d.maxStrLen || len(hf.Value) > d.maxStrLen {
+                       return ErrStringLength
+               }
+       }
+       if d.emitEnabled {
+               d.emit(hf)
+       }
+       return nil
+}
+
+// (same invariants and behavior as parseHeaderFieldRepr)
+func (d *Decoder) parseDynamicTableSizeUpdate() error {
+       buf := d.buf
+       size, buf, err := readVarInt(5, buf)
+       if err != nil {
+               return err
+       }
+       if size > uint64(d.dynTab.allowedMaxSize) {
+               return DecodingError{errors.New("dynamic table size update too large")}
+       }
+       d.dynTab.setMaxSize(uint32(size))
+       d.buf = buf
+       return nil
+}
+
+var errVarintOverflow = DecodingError{errors.New("varint integer overflow")}
+
+// readVarInt reads an unsigned variable length integer off the
+// beginning of p. n is the parameter as described in
+// http://http2.github.io/http2-spec/compression.html#rfc.section.5.1.
+//
+// n must always be between 1 and 8.
+//
+// The returned remain buffer is either a smaller suffix of p, or err != nil.
+// The error is errNeedMore if p doesn't contain a complete integer.
+func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) {
+       if n < 1 || n > 8 {
+               panic("bad n")
+       }
+       if len(p) == 0 {
+               return 0, p, errNeedMore
+       }
+       i = uint64(p[0])
+       if n < 8 {
+               i &= (1 << uint64(n)) - 1
+       }
+       if i < (1<<uint64(n))-1 {
+               return i, p[1:], nil
+       }
+
+       origP := p
+       p = p[1:]
+       var m uint64
+       for len(p) > 0 {
+               b := p[0]
+               p = p[1:]
+               i += uint64(b&127) << m
+               if b&128 == 0 {
+                       return i, p, nil
+               }
+               m += 7
+               if m >= 63 { // TODO: proper overflow check. making this up.
+                       return 0, origP, errVarintOverflow
+               }
+       }
+       return 0, origP, errNeedMore
+}
+
+// readString decodes an hpack string from p.
+//
+// wantStr is whether s will be used. If false, decompression and
+// []byte->string garbage are skipped if s will be ignored
+// anyway. This does mean that huffman decoding errors for non-indexed
+// strings past the MAX_HEADER_LIST_SIZE are ignored, but the server
+// is returning an error anyway, and because they're not indexed, the error
+// won't affect the decoding state.
+func (d *Decoder) readString(p []byte, wantStr bool) (s string, remain []byte, err error) {
+       if len(p) == 0 {
+               return "", p, errNeedMore
+       }
+       isHuff := p[0]&128 != 0
+       strLen, p, err := readVarInt(7, p)
+       if err != nil {
+               return "", p, err
+       }
+       if d.maxStrLen != 0 && strLen > uint64(d.maxStrLen) {
+               return "", nil, ErrStringLength
+       }
+       if uint64(len(p)) < strLen {
+               return "", p, errNeedMore
+       }
+       if !isHuff {
+               if wantStr {
+                       s = string(p[:strLen])
+               }
+               return s, p[strLen:], nil
+       }
+
+       if wantStr {
+               buf := bufPool.Get().(*bytes.Buffer)
+               buf.Reset() // don't trust others
+               defer bufPool.Put(buf)
+               if err := huffmanDecode(buf, d.maxStrLen, p[:strLen]); err != nil {
+                       buf.Reset()
+                       return "", nil, err
+               }
+               s = buf.String()
+               buf.Reset() // be nice to GC
+       }
+       return s, p[strLen:], nil
+}
diff --git a/libgo/go/internal/golang.org/x/net/http2/hpack/hpack_test.go b/libgo/go/internal/golang.org/x/net/http2/hpack/hpack_test.go
new file mode 100644 (file)
index 0000000..6dc69f9
--- /dev/null
@@ -0,0 +1,813 @@
+// 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 hpack
+
+import (
+       "bufio"
+       "bytes"
+       "encoding/hex"
+       "fmt"
+       "math/rand"
+       "reflect"
+       "regexp"
+       "strconv"
+       "strings"
+       "testing"
+       "time"
+)
+
+func TestStaticTable(t *testing.T) {
+       fromSpec := `
+          +-------+-----------------------------+---------------+
+          | 1     | :authority                  |               |
+          | 2     | :method                     | GET           |
+          | 3     | :method                     | POST          |
+          | 4     | :path                       | /             |
+          | 5     | :path                       | /index.html   |
+          | 6     | :scheme                     | http          |
+          | 7     | :scheme                     | https         |
+          | 8     | :status                     | 200           |
+          | 9     | :status                     | 204           |
+          | 10    | :status                     | 206           |
+          | 11    | :status                     | 304           |
+          | 12    | :status                     | 400           |
+          | 13    | :status                     | 404           |
+          | 14    | :status                     | 500           |
+          | 15    | accept-charset              |               |
+          | 16    | accept-encoding             | gzip, deflate |
+          | 17    | accept-language             |               |
+          | 18    | accept-ranges               |               |
+          | 19    | accept                      |               |
+          | 20    | access-control-allow-origin |               |
+          | 21    | age                         |               |
+          | 22    | allow                       |               |
+          | 23    | authorization               |               |
+          | 24    | cache-control               |               |
+          | 25    | content-disposition         |               |
+          | 26    | content-encoding            |               |
+          | 27    | content-language            |               |
+          | 28    | content-length              |               |
+          | 29    | content-location            |               |
+          | 30    | content-range               |               |
+          | 31    | content-type                |               |
+          | 32    | cookie                      |               |
+          | 33    | date                        |               |
+          | 34    | etag                        |               |
+          | 35    | expect                      |               |
+          | 36    | expires                     |               |
+          | 37    | from                        |               |
+          | 38    | host                        |               |
+          | 39    | if-match                    |               |
+          | 40    | if-modified-since           |               |
+          | 41    | if-none-match               |               |
+          | 42    | if-range                    |               |
+          | 43    | if-unmodified-since         |               |
+          | 44    | last-modified               |               |
+          | 45    | link                        |               |
+          | 46    | location                    |               |
+          | 47    | max-forwards                |               |
+          | 48    | proxy-authenticate          |               |
+          | 49    | proxy-authorization         |               |
+          | 50    | range                       |               |
+          | 51    | referer                     |               |
+          | 52    | refresh                     |               |
+          | 53    | retry-after                 |               |
+          | 54    | server                      |               |
+          | 55    | set-cookie                  |               |
+          | 56    | strict-transport-security   |               |
+          | 57    | transfer-encoding           |               |
+          | 58    | user-agent                  |               |
+          | 59    | vary                        |               |
+          | 60    | via                         |               |
+          | 61    | www-authenticate            |               |
+          +-------+-----------------------------+---------------+
+`
+       bs := bufio.NewScanner(strings.NewReader(fromSpec))
+       re := regexp.MustCompile(`\| (\d+)\s+\| (\S+)\s*\| (\S(.*\S)?)?\s+\|`)
+       for bs.Scan() {
+               l := bs.Text()
+               if !strings.Contains(l, "|") {
+                       continue
+               }
+               m := re.FindStringSubmatch(l)
+               if m == nil {
+                       continue
+               }
+               i, err := strconv.Atoi(m[1])
+               if err != nil {
+                       t.Errorf("Bogus integer on line %q", l)
+                       continue
+               }
+               if i < 1 || i > len(staticTable) {
+                       t.Errorf("Bogus index %d on line %q", i, l)
+                       continue
+               }
+               if got, want := staticTable[i-1].Name, m[2]; got != want {
+                       t.Errorf("header index %d name = %q; want %q", i, got, want)
+               }
+               if got, want := staticTable[i-1].Value, m[3]; got != want {
+                       t.Errorf("header index %d value = %q; want %q", i, got, want)
+               }
+       }
+       if err := bs.Err(); err != nil {
+               t.Error(err)
+       }
+}
+
+func (d *Decoder) mustAt(idx int) HeaderField {
+       if hf, ok := d.at(uint64(idx)); !ok {
+               panic(fmt.Sprintf("bogus index %d", idx))
+       } else {
+               return hf
+       }
+}
+
+func TestDynamicTableAt(t *testing.T) {
+       d := NewDecoder(4096, nil)
+       at := d.mustAt
+       if got, want := at(2), (pair(":method", "GET")); got != want {
+               t.Errorf("at(2) = %v; want %v", got, want)
+       }
+       d.dynTab.add(pair("foo", "bar"))
+       d.dynTab.add(pair("blake", "miz"))
+       if got, want := at(len(staticTable)+1), (pair("blake", "miz")); got != want {
+               t.Errorf("at(dyn 1) = %v; want %v", got, want)
+       }
+       if got, want := at(len(staticTable)+2), (pair("foo", "bar")); got != want {
+               t.Errorf("at(dyn 2) = %v; want %v", got, want)
+       }
+       if got, want := at(3), (pair(":method", "POST")); got != want {
+               t.Errorf("at(3) = %v; want %v", got, want)
+       }
+}
+
+func TestDynamicTableSearch(t *testing.T) {
+       dt := dynamicTable{}
+       dt.setMaxSize(4096)
+
+       dt.add(pair("foo", "bar"))
+       dt.add(pair("blake", "miz"))
+       dt.add(pair(":method", "GET"))
+
+       tests := []struct {
+               hf        HeaderField
+               wantI     uint64
+               wantMatch bool
+       }{
+               // Name and Value match
+               {pair("foo", "bar"), 3, true},
+               {pair(":method", "GET"), 1, true},
+
+               // Only name match because of Sensitive == true
+               {HeaderField{"blake", "miz", true}, 2, false},
+
+               // Only Name matches
+               {pair("foo", "..."), 3, false},
+               {pair("blake", "..."), 2, false},
+               {pair(":method", "..."), 1, false},
+
+               // None match
+               {pair("foo-", "bar"), 0, false},
+       }
+       for _, tt := range tests {
+               if gotI, gotMatch := dt.search(tt.hf); gotI != tt.wantI || gotMatch != tt.wantMatch {
+                       t.Errorf("d.search(%+v) = %v, %v; want %v, %v", tt.hf, gotI, gotMatch, tt.wantI, tt.wantMatch)
+               }
+       }
+}
+
+func TestDynamicTableSizeEvict(t *testing.T) {
+       d := NewDecoder(4096, nil)
+       if want := uint32(0); d.dynTab.size != want {
+               t.Fatalf("size = %d; want %d", d.dynTab.size, want)
+       }
+       add := d.dynTab.add
+       add(pair("blake", "eats pizza"))
+       if want := uint32(15 + 32); d.dynTab.size != want {
+               t.Fatalf("after pizza, size = %d; want %d", d.dynTab.size, want)
+       }
+       add(pair("foo", "bar"))
+       if want := uint32(15 + 32 + 6 + 32); d.dynTab.size != want {
+               t.Fatalf("after foo bar, size = %d; want %d", d.dynTab.size, want)
+       }
+       d.dynTab.setMaxSize(15 + 32 + 1 /* slop */)
+       if want := uint32(6 + 32); d.dynTab.size != want {
+               t.Fatalf("after setMaxSize, size = %d; want %d", d.dynTab.size, want)
+       }
+       if got, want := d.mustAt(len(staticTable)+1), (pair("foo", "bar")); got != want {
+               t.Errorf("at(dyn 1) = %v; want %v", got, want)
+       }
+       add(pair("long", strings.Repeat("x", 500)))
+       if want := uint32(0); d.dynTab.size != want {
+               t.Fatalf("after big one, size = %d; want %d", d.dynTab.size, want)
+       }
+}
+
+func TestDecoderDecode(t *testing.T) {
+       tests := []struct {
+               name       string
+               in         []byte
+               want       []HeaderField
+               wantDynTab []HeaderField // newest entry first
+       }{
+               // C.2.1 Literal Header Field with Indexing
+               // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.1
+               {"C.2.1", dehex("400a 6375 7374 6f6d 2d6b 6579 0d63 7573 746f 6d2d 6865 6164 6572"),
+                       []HeaderField{pair("custom-key", "custom-header")},
+                       []HeaderField{pair("custom-key", "custom-header")},
+               },
+
+               // C.2.2 Literal Header Field without Indexing
+               // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.2
+               {"C.2.2", dehex("040c 2f73 616d 706c 652f 7061 7468"),
+                       []HeaderField{pair(":path", "/sample/path")},
+                       []HeaderField{}},
+
+               // C.2.3 Literal Header Field never Indexed
+               // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.3
+               {"C.2.3", dehex("1008 7061 7373 776f 7264 0673 6563 7265 74"),
+                       []HeaderField{{"password", "secret", true}},
+                       []HeaderField{}},
+
+               // C.2.4 Indexed Header Field
+               // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.4
+               {"C.2.4", []byte("\x82"),
+                       []HeaderField{pair(":method", "GET")},
+                       []HeaderField{}},
+       }
+       for _, tt := range tests {
+               d := NewDecoder(4096, nil)
+               hf, err := d.DecodeFull(tt.in)
+               if err != nil {
+                       t.Errorf("%s: %v", tt.name, err)
+                       continue
+               }
+               if !reflect.DeepEqual(hf, tt.want) {
+                       t.Errorf("%s: Got %v; want %v", tt.name, hf, tt.want)
+               }
+               gotDynTab := d.dynTab.reverseCopy()
+               if !reflect.DeepEqual(gotDynTab, tt.wantDynTab) {
+                       t.Errorf("%s: dynamic table after = %v; want %v", tt.name, gotDynTab, tt.wantDynTab)
+               }
+       }
+}
+
+func (dt *dynamicTable) reverseCopy() (hf []HeaderField) {
+       hf = make([]HeaderField, len(dt.ents))
+       for i := range hf {
+               hf[i] = dt.ents[len(dt.ents)-1-i]
+       }
+       return
+}
+
+type encAndWant struct {
+       enc         []byte
+       want        []HeaderField
+       wantDynTab  []HeaderField
+       wantDynSize uint32
+}
+
+// C.3 Request Examples without Huffman Coding
+// http://http2.github.io/http2-spec/compression.html#rfc.section.C.3
+func TestDecodeC3_NoHuffman(t *testing.T) {
+       testDecodeSeries(t, 4096, []encAndWant{
+               {dehex("8286 8441 0f77 7777 2e65 7861 6d70 6c65 2e63 6f6d"),
+                       []HeaderField{
+                               pair(":method", "GET"),
+                               pair(":scheme", "http"),
+                               pair(":path", "/"),
+                               pair(":authority", "www.example.com"),
+                       },
+                       []HeaderField{
+                               pair(":authority", "www.example.com"),
+                       },
+                       57,
+               },
+               {dehex("8286 84be 5808 6e6f 2d63 6163 6865"),
+                       []HeaderField{
+                               pair(":method", "GET"),
+                               pair(":scheme", "http"),
+                               pair(":path", "/"),
+                               pair(":authority", "www.example.com"),
+                               pair("cache-control", "no-cache"),
+                       },
+                       []HeaderField{
+                               pair("cache-control", "no-cache"),
+                               pair(":authority", "www.example.com"),
+                       },
+                       110,
+               },
+               {dehex("8287 85bf 400a 6375 7374 6f6d 2d6b 6579 0c63 7573 746f 6d2d 7661 6c75 65"),
+                       []HeaderField{
+                               pair(":method", "GET"),
+                               pair(":scheme", "https"),
+                               pair(":path", "/index.html"),
+                               pair(":authority", "www.example.com"),
+                               pair("custom-key", "custom-value"),
+                       },
+                       []HeaderField{
+                               pair("custom-key", "custom-value"),
+                               pair("cache-control", "no-cache"),
+                               pair(":authority", "www.example.com"),
+                       },
+                       164,
+               },
+       })
+}
+
+// C.4 Request Examples with Huffman Coding
+// http://http2.github.io/http2-spec/compression.html#rfc.section.C.4
+func TestDecodeC4_Huffman(t *testing.T) {
+       testDecodeSeries(t, 4096, []encAndWant{
+               {dehex("8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4 ff"),
+                       []HeaderField{
+                               pair(":method", "GET"),
+                               pair(":scheme", "http"),
+                               pair(":path", "/"),
+                               pair(":authority", "www.example.com"),
+                       },
+                       []HeaderField{
+                               pair(":authority", "www.example.com"),
+                       },
+                       57,
+               },
+               {dehex("8286 84be 5886 a8eb 1064 9cbf"),
+                       []HeaderField{
+                               pair(":method", "GET"),
+                               pair(":scheme", "http"),
+                               pair(":path", "/"),
+                               pair(":authority", "www.example.com"),
+                               pair("cache-control", "no-cache"),
+                       },
+                       []HeaderField{
+                               pair("cache-control", "no-cache"),
+                               pair(":authority", "www.example.com"),
+                       },
+                       110,
+               },
+               {dehex("8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925 a849 e95b b8e8 b4bf"),
+                       []HeaderField{
+                               pair(":method", "GET"),
+                               pair(":scheme", "https"),
+                               pair(":path", "/index.html"),
+                               pair(":authority", "www.example.com"),
+                               pair("custom-key", "custom-value"),
+                       },
+                       []HeaderField{
+                               pair("custom-key", "custom-value"),
+                               pair("cache-control", "no-cache"),
+                               pair(":authority", "www.example.com"),
+                       },
+                       164,
+               },
+       })
+}
+
+// http://http2.github.io/http2-spec/compression.html#rfc.section.C.5
+// "This section shows several consecutive header lists, corresponding
+// to HTTP responses, on the same connection. The HTTP/2 setting
+// parameter SETTINGS_HEADER_TABLE_SIZE is set to the value of 256
+// octets, causing some evictions to occur."
+func TestDecodeC5_ResponsesNoHuff(t *testing.T) {
+       testDecodeSeries(t, 256, []encAndWant{
+               {dehex(`
+4803 3330 3258 0770 7269 7661 7465 611d
+4d6f 6e2c 2032 3120 4f63 7420 3230 3133
+2032 303a 3133 3a32 3120 474d 546e 1768
+7474 7073 3a2f 2f77 7777 2e65 7861 6d70
+6c65 2e63 6f6d
+`),
+                       []HeaderField{
+                               pair(":status", "302"),
+                               pair("cache-control", "private"),
+                               pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
+                               pair("location", "https://www.example.com"),
+                       },
+                       []HeaderField{
+                               pair("location", "https://www.example.com"),
+                               pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
+                               pair("cache-control", "private"),
+                               pair(":status", "302"),
+                       },
+                       222,
+               },
+               {dehex("4803 3330 37c1 c0bf"),
+                       []HeaderField{
+                               pair(":status", "307"),
+                               pair("cache-control", "private"),
+                               pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
+                               pair("location", "https://www.example.com"),
+                       },
+                       []HeaderField{
+                               pair(":status", "307"),
+                               pair("location", "https://www.example.com"),
+                               pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
+                               pair("cache-control", "private"),
+                       },
+                       222,
+               },
+               {dehex(`
+88c1 611d 4d6f 6e2c 2032 3120 4f63 7420
+3230 3133 2032 303a 3133 3a32 3220 474d
+54c0 5a04 677a 6970 7738 666f 6f3d 4153
+444a 4b48 514b 425a 584f 5157 454f 5049
+5541 5851 5745 4f49 553b 206d 6178 2d61
+6765 3d33 3630 303b 2076 6572 7369 6f6e
+3d31
+`),
+                       []HeaderField{
+                               pair(":status", "200"),
+                               pair("cache-control", "private"),
+                               pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
+                               pair("location", "https://www.example.com"),
+                               pair("content-encoding", "gzip"),
+                               pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
+                       },
+                       []HeaderField{
+                               pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
+                               pair("content-encoding", "gzip"),
+                               pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
+                       },
+                       215,
+               },
+       })
+}
+
+// http://http2.github.io/http2-spec/compression.html#rfc.section.C.6
+// "This section shows the same examples as the previous section, but
+// using Huffman encoding for the literal values. The HTTP/2 setting
+// parameter SETTINGS_HEADER_TABLE_SIZE is set to the value of 256
+// octets, causing some evictions to occur. The eviction mechanism
+// uses the length of the decoded literal values, so the same
+// evictions occurs as in the previous section."
+func TestDecodeC6_ResponsesHuffman(t *testing.T) {
+       testDecodeSeries(t, 256, []encAndWant{
+               {dehex(`
+4882 6402 5885 aec3 771a 4b61 96d0 7abe
+9410 54d4 44a8 2005 9504 0b81 66e0 82a6
+2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8
+e9ae 82ae 43d3
+`),
+                       []HeaderField{
+                               pair(":status", "302"),
+                               pair("cache-control", "private"),
+                               pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
+                               pair("location", "https://www.example.com"),
+                       },
+                       []HeaderField{
+                               pair("location", "https://www.example.com"),
+                               pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
+                               pair("cache-control", "private"),
+                               pair(":status", "302"),
+                       },
+                       222,
+               },
+               {dehex("4883 640e ffc1 c0bf"),
+                       []HeaderField{
+                               pair(":status", "307"),
+                               pair("cache-control", "private"),
+                               pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
+                               pair("location", "https://www.example.com"),
+                       },
+                       []HeaderField{
+                               pair(":status", "307"),
+                               pair("location", "https://www.example.com"),
+                               pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
+                               pair("cache-control", "private"),
+                       },
+                       222,
+               },
+               {dehex(`
+88c1 6196 d07a be94 1054 d444 a820 0595
+040b 8166 e084 a62d 1bff c05a 839b d9ab
+77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b
+3960 d5af 2708 7f36 72c1 ab27 0fb5 291f
+9587 3160 65c0 03ed 4ee5 b106 3d50 07
+`),
+                       []HeaderField{
+                               pair(":status", "200"),
+                               pair("cache-control", "private"),
+                               pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
+                               pair("location", "https://www.example.com"),
+                               pair("content-encoding", "gzip"),
+                               pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
+                       },
+                       []HeaderField{
+                               pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
+                               pair("content-encoding", "gzip"),
+                               pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
+                       },
+                       215,
+               },
+       })
+}
+
+func testDecodeSeries(t *testing.T, size uint32, steps []encAndWant) {
+       d := NewDecoder(size, nil)
+       for i, step := range steps {
+               hf, err := d.DecodeFull(step.enc)
+               if err != nil {
+                       t.Fatalf("Error at step index %d: %v", i, err)
+               }
+               if !reflect.DeepEqual(hf, step.want) {
+                       t.Fatalf("At step index %d: Got headers %v; want %v", i, hf, step.want)
+               }
+               gotDynTab := d.dynTab.reverseCopy()
+               if !reflect.DeepEqual(gotDynTab, step.wantDynTab) {
+                       t.Errorf("After step index %d, dynamic table = %v; want %v", i, gotDynTab, step.wantDynTab)
+               }
+               if d.dynTab.size != step.wantDynSize {
+                       t.Errorf("After step index %d, dynamic table size = %v; want %v", i, d.dynTab.size, step.wantDynSize)
+               }
+       }
+}
+
+func TestHuffmanDecode(t *testing.T) {
+       tests := []struct {
+               inHex, want string
+       }{
+               {"f1e3 c2e5 f23a 6ba0 ab90 f4ff", "www.example.com"},
+               {"a8eb 1064 9cbf", "no-cache"},
+               {"25a8 49e9 5ba9 7d7f", "custom-key"},
+               {"25a8 49e9 5bb8 e8b4 bf", "custom-value"},
+               {"6402", "302"},
+               {"aec3 771a 4b", "private"},
+               {"d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff", "Mon, 21 Oct 2013 20:13:21 GMT"},
+               {"9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3", "https://www.example.com"},
+               {"9bd9 ab", "gzip"},
+               {"94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07",
+                       "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
+       }
+       for i, tt := range tests {
+               var buf bytes.Buffer
+               in, err := hex.DecodeString(strings.Replace(tt.inHex, " ", "", -1))
+               if err != nil {
+                       t.Errorf("%d. hex input error: %v", i, err)
+                       continue
+               }
+               if _, err := HuffmanDecode(&buf, in); err != nil {
+                       t.Errorf("%d. decode error: %v", i, err)
+                       continue
+               }
+               if got := buf.String(); tt.want != got {
+                       t.Errorf("%d. decode = %q; want %q", i, got, tt.want)
+               }
+       }
+}
+
+func TestAppendHuffmanString(t *testing.T) {
+       tests := []struct {
+               in, want string
+       }{
+               {"www.example.com", "f1e3 c2e5 f23a 6ba0 ab90 f4ff"},
+               {"no-cache", "a8eb 1064 9cbf"},
+               {"custom-key", "25a8 49e9 5ba9 7d7f"},
+               {"custom-value", "25a8 49e9 5bb8 e8b4 bf"},
+               {"302", "6402"},
+               {"private", "aec3 771a 4b"},
+               {"Mon, 21 Oct 2013 20:13:21 GMT", "d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff"},
+               {"https://www.example.com", "9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3"},
+               {"gzip", "9bd9 ab"},
+               {"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1",
+                       "94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07"},
+       }
+       for i, tt := range tests {
+               buf := []byte{}
+               want := strings.Replace(tt.want, " ", "", -1)
+               buf = AppendHuffmanString(buf, tt.in)
+               if got := hex.EncodeToString(buf); want != got {
+                       t.Errorf("%d. encode = %q; want %q", i, got, want)
+               }
+       }
+}
+
+func TestHuffmanMaxStrLen(t *testing.T) {
+       const msg = "Some string"
+       huff := AppendHuffmanString(nil, msg)
+
+       testGood := func(max int) {
+               var out bytes.Buffer
+               if err := huffmanDecode(&out, max, huff); err != nil {
+                       t.Errorf("For maxLen=%d, unexpected error: %v", max, err)
+               }
+               if out.String() != msg {
+                       t.Errorf("For maxLen=%d, out = %q; want %q", max, out.String(), msg)
+               }
+       }
+       testGood(0)
+       testGood(len(msg))
+       testGood(len(msg) + 1)
+
+       var out bytes.Buffer
+       if err := huffmanDecode(&out, len(msg)-1, huff); err != ErrStringLength {
+               t.Errorf("err = %v; want ErrStringLength", err)
+       }
+}
+
+func TestHuffmanRoundtripStress(t *testing.T) {
+       const Len = 50 // of uncompressed string
+       input := make([]byte, Len)
+       var output bytes.Buffer
+       var huff []byte
+
+       n := 5000
+       if testing.Short() {
+               n = 100
+       }
+       seed := time.Now().UnixNano()
+       t.Logf("Seed = %v", seed)
+       src := rand.New(rand.NewSource(seed))
+       var encSize int64
+       for i := 0; i < n; i++ {
+               for l := range input {
+                       input[l] = byte(src.Intn(256))
+               }
+               huff = AppendHuffmanString(huff[:0], string(input))
+               encSize += int64(len(huff))
+               output.Reset()
+               if err := huffmanDecode(&output, 0, huff); err != nil {
+                       t.Errorf("Failed to decode %q -> %q -> error %v", input, huff, err)
+                       continue
+               }
+               if !bytes.Equal(output.Bytes(), input) {
+                       t.Errorf("Roundtrip failure on %q -> %q -> %q", input, huff, output.Bytes())
+               }
+       }
+       t.Logf("Compressed size of original: %0.02f%% (%v -> %v)", 100*(float64(encSize)/(Len*float64(n))), Len*n, encSize)
+}
+
+func TestHuffmanDecodeFuzz(t *testing.T) {
+       const Len = 50 // of compressed
+       var buf, zbuf bytes.Buffer
+
+       n := 5000
+       if testing.Short() {
+               n = 100
+       }
+       seed := time.Now().UnixNano()
+       t.Logf("Seed = %v", seed)
+       src := rand.New(rand.NewSource(seed))
+       numFail := 0
+       for i := 0; i < n; i++ {
+               zbuf.Reset()
+               if i == 0 {
+                       // Start with at least one invalid one.
+                       zbuf.WriteString("00\x91\xff\xff\xff\xff\xc8")
+               } else {
+                       for l := 0; l < Len; l++ {
+                               zbuf.WriteByte(byte(src.Intn(256)))
+                       }
+               }
+
+               buf.Reset()
+               if err := huffmanDecode(&buf, 0, zbuf.Bytes()); err != nil {
+                       if err == ErrInvalidHuffman {
+                               numFail++
+                               continue
+                       }
+                       t.Errorf("Failed to decode %q: %v", zbuf.Bytes(), err)
+                       continue
+               }
+       }
+       t.Logf("%0.02f%% are invalid (%d / %d)", 100*float64(numFail)/float64(n), numFail, n)
+       if numFail < 1 {
+               t.Error("expected at least one invalid huffman encoding (test starts with one)")
+       }
+}
+
+func TestReadVarInt(t *testing.T) {
+       type res struct {
+               i        uint64
+               consumed int
+               err      error
+       }
+       tests := []struct {
+               n    byte
+               p    []byte
+               want res
+       }{
+               // Fits in a byte:
+               {1, []byte{0}, res{0, 1, nil}},
+               {2, []byte{2}, res{2, 1, nil}},
+               {3, []byte{6}, res{6, 1, nil}},
+               {4, []byte{14}, res{14, 1, nil}},
+               {5, []byte{30}, res{30, 1, nil}},
+               {6, []byte{62}, res{62, 1, nil}},
+               {7, []byte{126}, res{126, 1, nil}},
+               {8, []byte{254}, res{254, 1, nil}},
+
+               // Doesn't fit in a byte:
+               {1, []byte{1}, res{0, 0, errNeedMore}},
+               {2, []byte{3}, res{0, 0, errNeedMore}},
+               {3, []byte{7}, res{0, 0, errNeedMore}},
+               {4, []byte{15}, res{0, 0, errNeedMore}},
+               {5, []byte{31}, res{0, 0, errNeedMore}},
+               {6, []byte{63}, res{0, 0, errNeedMore}},
+               {7, []byte{127}, res{0, 0, errNeedMore}},
+               {8, []byte{255}, res{0, 0, errNeedMore}},
+
+               // Ignoring top bits:
+               {5, []byte{255, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 111
+               {5, []byte{159, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 100
+               {5, []byte{191, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 101
+
+               // Extra byte:
+               {5, []byte{191, 154, 10, 2}, res{1337, 3, nil}}, // extra byte
+
+               // Short a byte:
+               {5, []byte{191, 154}, res{0, 0, errNeedMore}},
+
+               // integer overflow:
+               {1, []byte{255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}, res{0, 0, errVarintOverflow}},
+       }
+       for _, tt := range tests {
+               i, remain, err := readVarInt(tt.n, tt.p)
+               consumed := len(tt.p) - len(remain)
+               got := res{i, consumed, err}
+               if got != tt.want {
+                       t.Errorf("readVarInt(%d, %v ~ %x) = %+v; want %+v", tt.n, tt.p, tt.p, got, tt.want)
+               }
+       }
+}
+
+// Fuzz crash, originally reported at https://github.com/bradfitz/http2/issues/56
+func TestHuffmanFuzzCrash(t *testing.T) {
+       got, err := HuffmanDecodeToString([]byte("00\x91\xff\xff\xff\xff\xc8"))
+       if got != "" {
+               t.Errorf("Got %q; want empty string", got)
+       }
+       if err != ErrInvalidHuffman {
+               t.Errorf("Err = %v; want ErrInvalidHuffman", err)
+       }
+}
+
+func dehex(s string) []byte {
+       s = strings.Replace(s, " ", "", -1)
+       s = strings.Replace(s, "\n", "", -1)
+       b, err := hex.DecodeString(s)
+       if err != nil {
+               panic(err)
+       }
+       return b
+}
+
+func TestEmitEnabled(t *testing.T) {
+       var buf bytes.Buffer
+       enc := NewEncoder(&buf)
+       enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
+       enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
+
+       numCallback := 0
+       var dec *Decoder
+       dec = NewDecoder(8<<20, func(HeaderField) {
+               numCallback++
+               dec.SetEmitEnabled(false)
+       })
+       if !dec.EmitEnabled() {
+               t.Errorf("initial emit enabled = false; want true")
+       }
+       if _, err := dec.Write(buf.Bytes()); err != nil {
+               t.Error(err)
+       }
+       if numCallback != 1 {
+               t.Errorf("num callbacks = %d; want 1", numCallback)
+       }
+       if dec.EmitEnabled() {
+               t.Errorf("emit enabled = true; want false")
+       }
+}
+
+func TestSaveBufLimit(t *testing.T) {
+       const maxStr = 1 << 10
+       var got []HeaderField
+       dec := NewDecoder(initialHeaderTableSize, func(hf HeaderField) {
+               got = append(got, hf)
+       })
+       dec.SetMaxStringLength(maxStr)
+       var frag []byte
+       frag = append(frag[:0], encodeTypeByte(false, false))
+       frag = appendVarInt(frag, 7, 3)
+       frag = append(frag, "foo"...)
+       frag = appendVarInt(frag, 7, 3)
+       frag = append(frag, "bar"...)
+
+       if _, err := dec.Write(frag); err != nil {
+               t.Fatal(err)
+       }
+
+       want := []HeaderField{{Name: "foo", Value: "bar"}}
+       if !reflect.DeepEqual(got, want) {
+               t.Errorf("After small writes, got %v; want %v", got, want)
+       }
+
+       frag = append(frag[:0], encodeTypeByte(false, false))
+       frag = appendVarInt(frag, 7, maxStr*3)
+       frag = append(frag, make([]byte, maxStr*3)...)
+
+       _, err := dec.Write(frag)
+       if err != ErrStringLength {
+               t.Fatalf("Write error = %v; want ErrStringLength", err)
+       }
+}
diff --git a/libgo/go/internal/golang.org/x/net/http2/hpack/huffman.go b/libgo/go/internal/golang.org/x/net/http2/hpack/huffman.go
new file mode 100644 (file)
index 0000000..eb4b1f0
--- /dev/null
@@ -0,0 +1,190 @@
+// 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 hpack
+
+import (
+       "bytes"
+       "errors"
+       "io"
+       "sync"
+)
+
+var bufPool = sync.Pool{
+       New: func() interface{} { return new(bytes.Buffer) },
+}
+
+// HuffmanDecode decodes the string in v and writes the expanded
+// result to w, returning the number of bytes written to w and the
+// Write call's return value. At most one Write call is made.
+func HuffmanDecode(w io.Writer, v []byte) (int, error) {
+       buf := bufPool.Get().(*bytes.Buffer)
+       buf.Reset()
+       defer bufPool.Put(buf)
+       if err := huffmanDecode(buf, 0, v); err != nil {
+               return 0, err
+       }
+       return w.Write(buf.Bytes())
+}
+
+// HuffmanDecodeToString decodes the string in v.
+func HuffmanDecodeToString(v []byte) (string, error) {
+       buf := bufPool.Get().(*bytes.Buffer)
+       buf.Reset()
+       defer bufPool.Put(buf)
+       if err := huffmanDecode(buf, 0, v); err != nil {
+               return "", err
+       }
+       return buf.String(), nil
+}
+
+// ErrInvalidHuffman is returned for errors found decoding
+// Huffman-encoded strings.
+var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data")
+
+// huffmanDecode decodes v to buf.
+// If maxLen is greater than 0, attempts to write more to buf than
+// maxLen bytes will return ErrStringLength.
+func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
+       n := rootHuffmanNode
+       cur, nbits := uint(0), uint8(0)
+       for _, b := range v {
+               cur = cur<<8 | uint(b)
+               nbits += 8
+               for nbits >= 8 {
+                       idx := byte(cur >> (nbits - 8))
+                       n = n.children[idx]
+                       if n == nil {
+                               return ErrInvalidHuffman
+                       }
+                       if n.children == nil {
+                               if maxLen != 0 && buf.Len() == maxLen {
+                                       return ErrStringLength
+                               }
+                               buf.WriteByte(n.sym)
+                               nbits -= n.codeLen
+                               n = rootHuffmanNode
+                       } else {
+                               nbits -= 8
+                       }
+               }
+       }
+       for nbits > 0 {
+               n = n.children[byte(cur<<(8-nbits))]
+               if n.children != nil || n.codeLen > nbits {
+                       break
+               }
+               buf.WriteByte(n.sym)
+               nbits -= n.codeLen
+               n = rootHuffmanNode
+       }
+       return nil
+}
+
+type node struct {
+       // children is non-nil for internal nodes
+       children []*node
+
+       // The following are only valid if children is nil:
+       codeLen uint8 // number of bits that led to the output of sym
+       sym     byte  // output symbol
+}
+
+func newInternalNode() *node {
+       return &node{children: make([]*node, 256)}
+}
+
+var rootHuffmanNode = newInternalNode()
+
+func init() {
+       if len(huffmanCodes) != 256 {
+               panic("unexpected size")
+       }
+       for i, code := range huffmanCodes {
+               addDecoderNode(byte(i), code, huffmanCodeLen[i])
+       }
+}
+
+func addDecoderNode(sym byte, code uint32, codeLen uint8) {
+       cur := rootHuffmanNode
+       for codeLen > 8 {
+               codeLen -= 8
+               i := uint8(code >> codeLen)
+               if cur.children[i] == nil {
+                       cur.children[i] = newInternalNode()
+               }
+               cur = cur.children[i]
+       }
+       shift := 8 - codeLen
+       start, end := int(uint8(code<<shift)), int(1<<shift)
+       for i := start; i < start+end; i++ {
+               cur.children[i] = &node{sym: sym, codeLen: codeLen}
+       }
+}
+
+// AppendHuffmanString appends s, as encoded in Huffman codes, to dst
+// and returns the extended buffer.
+func AppendHuffmanString(dst []byte, s string) []byte {
+       rembits := uint8(8)
+
+       for i := 0; i < len(s); i++ {
+               if rembits == 8 {
+                       dst = append(dst, 0)
+               }
+               dst, rembits = appendByteToHuffmanCode(dst, rembits, s[i])
+       }
+
+       if rembits < 8 {
+               // special EOS symbol
+               code := uint32(0x3fffffff)
+               nbits := uint8(30)
+
+               t := uint8(code >> (nbits - rembits))
+               dst[len(dst)-1] |= t
+       }
+
+       return dst
+}
+
+// HuffmanEncodeLength returns the number of bytes required to encode
+// s in Huffman codes. The result is round up to byte boundary.
+func HuffmanEncodeLength(s string) uint64 {
+       n := uint64(0)
+       for i := 0; i < len(s); i++ {
+               n += uint64(huffmanCodeLen[s[i]])
+       }
+       return (n + 7) / 8
+}
+
+// appendByteToHuffmanCode appends Huffman code for c to dst and
+// returns the extended buffer and the remaining bits in the last
+// element. The appending is not byte aligned and the remaining bits
+// in the last element of dst is given in rembits.
+func appendByteToHuffmanCode(dst []byte, rembits uint8, c byte) ([]byte, uint8) {
+       code := huffmanCodes[c]
+       nbits := huffmanCodeLen[c]
+
+       for {
+               if rembits > nbits {
+                       t := uint8(code << (rembits - nbits))
+                       dst[len(dst)-1] |= t
+                       rembits -= nbits
+                       break
+               }
+
+               t := uint8(code >> (nbits - rembits))
+               dst[len(dst)-1] |= t
+
+               nbits -= rembits
+               rembits = 8
+
+               if nbits == 0 {
+                       break
+               }
+
+               dst = append(dst, 0)
+       }
+
+       return dst, rembits
+}
diff --git a/libgo/go/internal/golang.org/x/net/http2/hpack/tables.go b/libgo/go/internal/golang.org/x/net/http2/hpack/tables.go
new file mode 100644 (file)
index 0000000..b9283a0
--- /dev/null
@@ -0,0 +1,352 @@
+// 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 hpack
+
+func pair(name, value string) HeaderField {
+       return HeaderField{Name: name, Value: value}
+}
+
+// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-B
+var staticTable = [...]HeaderField{
+       pair(":authority", ""), // index 1 (1-based)
+       pair(":method", "GET"),
+       pair(":method", "POST"),
+       pair(":path", "/"),
+       pair(":path", "/index.html"),
+       pair(":scheme", "http"),
+       pair(":scheme", "https"),
+       pair(":status", "200"),
+       pair(":status", "204"),
+       pair(":status", "206"),
+       pair(":status", "304"),
+       pair(":status", "400"),
+       pair(":status", "404"),
+       pair(":status", "500"),
+       pair("accept-charset", ""),
+       pair("accept-encoding", "gzip, deflate"),
+       pair("accept-language", ""),
+       pair("accept-ranges", ""),
+       pair("accept", ""),
+       pair("access-control-allow-origin", ""),
+       pair("age", ""),
+       pair("allow", ""),
+       pair("authorization", ""),
+       pair("cache-control", ""),
+       pair("content-disposition", ""),
+       pair("content-encoding", ""),
+       pair("content-language", ""),
+       pair("content-length", ""),
+       pair("content-location", ""),
+       pair("content-range", ""),
+       pair("content-type", ""),
+       pair("cookie", ""),
+       pair("date", ""),
+       pair("etag", ""),
+       pair("expect", ""),
+       pair("expires", ""),
+       pair("from", ""),
+       pair("host", ""),
+       pair("if-match", ""),
+       pair("if-modified-since", ""),
+       pair("if-none-match", ""),
+       pair("if-range", ""),
+       pair("if-unmodified-since", ""),
+       pair("last-modified", ""),
+       pair("link", ""),
+       pair("location", ""),
+       pair("max-forwards", ""),
+       pair("proxy-authenticate", ""),
+       pair("proxy-authorization", ""),
+       pair("range", ""),
+       pair("referer", ""),
+       pair("refresh", ""),
+       pair("retry-after", ""),
+       pair("server", ""),
+       pair("set-cookie", ""),
+       pair("strict-transport-security", ""),
+       pair("transfer-encoding", ""),
+       pair("user-agent", ""),
+       pair("vary", ""),
+       pair("via", ""),
+       pair("www-authenticate", ""),
+}
+
+var huffmanCodes = [256]uint32{
+       0x1ff8,
+       0x7fffd8,
+       0xfffffe2,
+       0xfffffe3,
+       0xfffffe4,
+       0xfffffe5,
+       0xfffffe6,
+       0xfffffe7,
+       0xfffffe8,
+       0xffffea,
+       0x3ffffffc,
+       0xfffffe9,
+       0xfffffea,
+       0x3ffffffd,
+       0xfffffeb,
+       0xfffffec,
+       0xfffffed,
+       0xfffffee,
+       0xfffffef,
+       0xffffff0,
+       0xffffff1,
+       0xffffff2,
+       0x3ffffffe,
+       0xffffff3,
+       0xffffff4,
+       0xffffff5,
+       0xffffff6,
+       0xffffff7,
+       0xffffff8,
+       0xffffff9,
+       0xffffffa,
+       0xffffffb,
+       0x14,
+       0x3f8,
+       0x3f9,
+       0xffa,
+       0x1ff9,
+       0x15,
+       0xf8,
+       0x7fa,
+       0x3fa,
+       0x3fb,
+       0xf9,
+       0x7fb,
+       0xfa,
+       0x16,
+       0x17,
+       0x18,
+       0x0,
+       0x1,
+       0x2,
+       0x19,
+       0x1a,
+       0x1b,
+       0x1c,
+       0x1d,
+       0x1e,
+       0x1f,
+       0x5c,
+       0xfb,
+       0x7ffc,
+       0x20,
+       0xffb,
+       0x3fc,
+       0x1ffa,
+       0x21,
+       0x5d,
+       0x5e,
+       0x5f,
+       0x60,
+       0x61,
+       0x62,
+       0x63,
+       0x64,
+       0x65,
+       0x66,
+       0x67,
+       0x68,
+       0x69,
+       0x6a,
+       0x6b,
+       0x6c,
+       0x6d,
+       0x6e,
+       0x6f,
+       0x70,
+       0x71,
+       0x72,
+       0xfc,
+       0x73,
+       0xfd,
+       0x1ffb,
+       0x7fff0,
+       0x1ffc,
+       0x3ffc,
+       0x22,
+       0x7ffd,
+       0x3,
+       0x23,
+       0x4,
+       0x24,
+       0x5,
+       0x25,
+       0x26,
+       0x27,
+       0x6,
+       0x74,
+       0x75,
+       0x28,
+       0x29,
+       0x2a,
+       0x7,
+       0x2b,
+       0x76,
+       0x2c,
+       0x8,
+       0x9,
+       0x2d,
+       0x77,
+       0x78,
+       0x79,
+       0x7a,
+       0x7b,
+       0x7ffe,
+       0x7fc,
+       0x3ffd,
+       0x1ffd,
+       0xffffffc,
+       0xfffe6,
+       0x3fffd2,
+       0xfffe7,
+       0xfffe8,
+       0x3fffd3,
+       0x3fffd4,
+       0x3fffd5,
+       0x7fffd9,
+       0x3fffd6,
+       0x7fffda,
+       0x7fffdb,
+       0x7fffdc,
+       0x7fffdd,
+       0x7fffde,
+       0xffffeb,
+       0x7fffdf,
+       0xffffec,
+       0xffffed,
+       0x3fffd7,
+       0x7fffe0,
+       0xffffee,
+       0x7fffe1,
+       0x7fffe2,
+       0x7fffe3,
+       0x7fffe4,
+       0x1fffdc,
+       0x3fffd8,
+       0x7fffe5,
+       0x3fffd9,
+       0x7fffe6,
+       0x7fffe7,
+       0xffffef,
+       0x3fffda,
+       0x1fffdd,
+       0xfffe9,
+       0x3fffdb,
+       0x3fffdc,
+       0x7fffe8,
+       0x7fffe9,
+       0x1fffde,
+       0x7fffea,
+       0x3fffdd,
+       0x3fffde,
+       0xfffff0,
+       0x1fffdf,
+       0x3fffdf,
+       0x7fffeb,
+       0x7fffec,
+       0x1fffe0,
+       0x1fffe1,
+       0x3fffe0,
+       0x1fffe2,
+       0x7fffed,
+       0x3fffe1,
+       0x7fffee,
+       0x7fffef,
+       0xfffea,
+       0x3fffe2,
+       0x3fffe3,
+       0x3fffe4,
+       0x7ffff0,
+       0x3fffe5,
+       0x3fffe6,
+       0x7ffff1,
+       0x3ffffe0,
+       0x3ffffe1,
+       0xfffeb,
+       0x7fff1,
+       0x3fffe7,
+       0x7ffff2,
+       0x3fffe8,
+       0x1ffffec,
+       0x3ffffe2,
+       0x3ffffe3,
+       0x3ffffe4,
+       0x7ffffde,
+       0x7ffffdf,
+       0x3ffffe5,
+       0xfffff1,
+       0x1ffffed,
+       0x7fff2,
+       0x1fffe3,
+       0x3ffffe6,
+       0x7ffffe0,
+       0x7ffffe1,
+       0x3ffffe7,
+       0x7ffffe2,
+       0xfffff2,
+       0x1fffe4,
+       0x1fffe5,
+       0x3ffffe8,
+       0x3ffffe9,
+       0xffffffd,
+       0x7ffffe3,
+       0x7ffffe4,
+       0x7ffffe5,
+       0xfffec,
+       0xfffff3,
+       0xfffed,
+       0x1fffe6,
+       0x3fffe9,
+       0x1fffe7,
+       0x1fffe8,
+       0x7ffff3,
+       0x3fffea,
+       0x3fffeb,
+       0x1ffffee,
+       0x1ffffef,
+       0xfffff4,
+       0xfffff5,
+       0x3ffffea,
+       0x7ffff4,
+       0x3ffffeb,
+       0x7ffffe6,
+       0x3ffffec,
+       0x3ffffed,
+       0x7ffffe7,
+       0x7ffffe8,
+       0x7ffffe9,
+       0x7ffffea,
+       0x7ffffeb,
+       0xffffffe,
+       0x7ffffec,
+       0x7ffffed,
+       0x7ffffee,
+       0x7ffffef,
+       0x7fffff0,
+       0x3ffffee,
+}
+
+var huffmanCodeLen = [256]uint8{
+       13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28,
+       28, 28, 28, 28, 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+       6, 10, 10, 12, 13, 6, 8, 11, 10, 10, 8, 11, 8, 6, 6, 6,
+       5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 8, 15, 6, 12, 10,
+       13, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+       7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 13, 19, 13, 14, 6,
+       15, 5, 6, 5, 6, 5, 6, 6, 6, 5, 7, 7, 6, 6, 6, 5,
+       6, 7, 6, 5, 5, 6, 7, 7, 7, 7, 7, 15, 11, 14, 13, 28,
+       20, 22, 20, 20, 22, 22, 22, 23, 22, 23, 23, 23, 23, 23, 24, 23,
+       24, 24, 22, 23, 24, 23, 23, 23, 23, 21, 22, 23, 22, 23, 23, 24,
+       22, 21, 20, 22, 22, 23, 23, 21, 23, 22, 22, 24, 21, 22, 23, 23,
+       21, 21, 22, 21, 23, 22, 23, 23, 20, 22, 22, 22, 23, 22, 22, 23,
+       26, 26, 20, 19, 22, 23, 22, 25, 26, 26, 26, 27, 27, 26, 24, 25,
+       19, 21, 26, 27, 27, 26, 27, 24, 21, 21, 26, 26, 28, 27, 27, 27,
+       20, 24, 20, 21, 22, 21, 21, 23, 22, 22, 25, 25, 24, 24, 26, 23,
+       26, 27, 26, 26, 27, 27, 27, 27, 27, 28, 27, 27, 27, 27, 27, 26,
+}
diff --git a/libgo/go/internal/race/doc.go b/libgo/go/internal/race/doc.go
new file mode 100644 (file)
index 0000000..d6a2243
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2015 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 race contains helper functions for manually instrumenting code for the race detector.
+
+The runtime package intentionally exports these functions only in the race build;
+this package exports them unconditionally but without the "race" build tag they are no-ops.
+*/
+package race
diff --git a/libgo/go/internal/race/norace.go b/libgo/go/internal/race/norace.go
new file mode 100644 (file)
index 0000000..d9049eb
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2015 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 race
+
+import (
+       "unsafe"
+)
+
+const Enabled = false
+
+func Acquire(addr unsafe.Pointer) {
+}
+
+func Release(addr unsafe.Pointer) {
+}
+
+func ReleaseMerge(addr unsafe.Pointer) {
+}
+
+func Disable() {
+}
+
+func Enable() {
+}
+
+func Read(addr unsafe.Pointer) {
+}
+
+func Write(addr unsafe.Pointer) {
+}
+
+func ReadRange(addr unsafe.Pointer, len int) {
+}
+
+func WriteRange(addr unsafe.Pointer, len int) {
+}
diff --git a/libgo/go/internal/race/race.go b/libgo/go/internal/race/race.go
new file mode 100644 (file)
index 0000000..cb0e773
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright 2015 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 race
+
+import (
+       "runtime"
+       "unsafe"
+)
+
+const Enabled = true
+
+func Acquire(addr unsafe.Pointer) {
+       runtime.RaceAcquire(addr)
+}
+
+func Release(addr unsafe.Pointer) {
+       runtime.RaceRelease(addr)
+}
+
+func ReleaseMerge(addr unsafe.Pointer) {
+       runtime.RaceReleaseMerge(addr)
+}
+
+func Disable() {
+       runtime.RaceDisable()
+}
+
+func Enable() {
+       runtime.RaceEnable()
+}
+
+func Read(addr unsafe.Pointer) {
+       runtime.RaceRead(addr)
+}
+
+func Write(addr unsafe.Pointer) {
+       runtime.RaceWrite(addr)
+}
+
+func ReadRange(addr unsafe.Pointer, len int) {
+       runtime.RaceReadRange(addr, len)
+}
+
+func WriteRange(addr unsafe.Pointer, len int) {
+       runtime.RaceWriteRange(addr, len)
+}
index 7388271ef1917b76c9ba6cb31df94248ae923cd7..e07557a93ba93c9a0642a142f6a7e5fe36ec6439 100644 (file)
@@ -5,20 +5,11 @@
 package unix
 
 import (
-       "runtime"
        "sync/atomic"
        "syscall"
        "unsafe"
 )
 
-var randomTrap = map[string]uintptr{
-       "386":     355,
-       "amd64":   318,
-       "arm":     384,
-       "ppc64":   359,
-       "ppc64le": 359,
-}[runtime.GOARCH]
-
 var randomUnsupported int32 // atomic
 
 // GetRandomFlag is a flag supported by the getrandom system call.
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_386.go b/libgo/go/internal/syscall/unix/getrandom_linux_386.go
new file mode 100644 (file)
index 0000000..48c69b4
--- /dev/null
@@ -0,0 +1,7 @@
+// 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 unix
+
+const randomTrap uintptr = 355
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_amd64.go b/libgo/go/internal/syscall/unix/getrandom_linux_amd64.go
new file mode 100644 (file)
index 0000000..7175e36
--- /dev/null
@@ -0,0 +1,7 @@
+// 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 unix
+
+const randomTrap uintptr = 318
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_arm.go b/libgo/go/internal/syscall/unix/getrandom_linux_arm.go
new file mode 100644 (file)
index 0000000..c4d6f43
--- /dev/null
@@ -0,0 +1,7 @@
+// 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 unix
+
+const randomTrap uintptr = 384
similarity index 57%
rename from libgo/go/go/constant/go14.go
rename to libgo/go/internal/syscall/unix/getrandom_linux_generic.go
index 2ab6da02f67045cc7b5b4acdb984c9a270e2678b..0e632dc27a4ff11442d202957c49de066bd1bda2 100644 (file)
@@ -2,12 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build go1.4
+// +build arm64
 
-package constant
+package unix
 
-import "math/big"
-
-func ratToFloat32(x *big.Rat) (float32, bool) {
-       return x.Float32()
-}
+const randomTrap uintptr = 278
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_mips64x.go b/libgo/go/internal/syscall/unix/getrandom_linux_mips64x.go
new file mode 100644 (file)
index 0000000..8531db6
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2015 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 mips64 mips64le
+
+package unix
+
+const randomTrap uintptr = 5313
diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_ppc64x.go b/libgo/go/internal/syscall/unix/getrandom_linux_ppc64x.go
new file mode 100644 (file)
index 0000000..6edaba2
--- /dev/null
@@ -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.
+
+// +build ppc64 ppc64le
+
+package unix
+
+const randomTrap uintptr = 359
index 07eccb23d8ffd70ae97f7ba5e1cb3a1f51329be9..a63c42022d159488e33c44dc6ae21c15b04f02ed 100644 (file)
@@ -12,6 +12,7 @@ import (
        "os"
        "syscall"
        "testing"
+       "unsafe"
 
        "internal/syscall/windows/registry"
 )
@@ -676,3 +677,76 @@ func TestInvalidValues(t *testing.T) {
                }
        }
 }
+
+func TestGetMUIStringValue(t *testing.T) {
+       if err := registry.LoadRegLoadMUIString(); err != nil {
+               t.Skip("regLoadMUIString not supported; skipping")
+       }
+       if err := procGetDynamicTimeZoneInformation.Find(); err != nil {
+               t.Skipf("%s not supported; skipping", procGetDynamicTimeZoneInformation.Name)
+       }
+       var dtzi DynamicTimezoneinformation
+       if _, err := GetDynamicTimeZoneInformation(&dtzi); err != nil {
+               t.Fatal(err)
+       }
+       tzKeyName := syscall.UTF16ToString(dtzi.TimeZoneKeyName[:])
+       timezoneK, err := registry.OpenKey(registry.LOCAL_MACHINE,
+               `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\`+tzKeyName, registry.READ)
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer timezoneK.Close()
+
+       type testType struct {
+               name string
+               want string
+       }
+       var tests = []testType{
+               {"MUI_Std", syscall.UTF16ToString(dtzi.StandardName[:])},
+       }
+       if dtzi.DynamicDaylightTimeDisabled == 0 {
+               tests = append(tests, testType{"MUI_Dlt", syscall.UTF16ToString(dtzi.DaylightName[:])})
+       }
+
+       for _, test := range tests {
+               got, err := timezoneK.GetMUIStringValue(test.name)
+               if err != nil {
+                       t.Error("GetMUIStringValue:", err)
+               }
+
+               if got != test.want {
+                       t.Errorf("GetMUIStringValue: %s: Got %q, want %q", test.name, got, test.want)
+               }
+       }
+}
+
+type DynamicTimezoneinformation struct {
+       Bias                        int32
+       StandardName                [32]uint16
+       StandardDate                syscall.Systemtime
+       StandardBias                int32
+       DaylightName                [32]uint16
+       DaylightDate                syscall.Systemtime
+       DaylightBias                int32
+       TimeZoneKeyName             [128]uint16
+       DynamicDaylightTimeDisabled uint8
+}
+
+var (
+       kernel32DLL = syscall.NewLazyDLL("kernel32")
+
+       procGetDynamicTimeZoneInformation = kernel32DLL.NewProc("GetDynamicTimeZoneInformation")
+)
+
+func GetDynamicTimeZoneInformation(dtzi *DynamicTimezoneinformation) (rc uint32, err error) {
+       r0, _, e1 := syscall.Syscall(procGetDynamicTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(dtzi)), 0, 0)
+       rc = uint32(r0)
+       if rc == 0xffffffff {
+               if e1 != 0 {
+                       err = error(e1)
+               } else {
+                       err = syscall.EINVAL
+               }
+       }
+       return
+}
index 38e573fd22705769de0fc887c238680b1f7ef977..5426cae90963308313cc186026e9187dcd0b6b78 100644 (file)
@@ -19,10 +19,15 @@ const (
        _ERROR_NO_MORE_ITEMS syscall.Errno = 259
 )
 
+func LoadRegLoadMUIString() error {
+       return procRegLoadMUIStringW.Find()
+}
+
 //sys  regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) = advapi32.RegCreateKeyExW
 //sys  regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) = advapi32.RegDeleteKeyW
 //sys  regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) = advapi32.RegSetValueExW
 //sys  regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegEnumValueW
 //sys  regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) = advapi32.RegDeleteValueW
+//sys   regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) = advapi32.RegLoadMUIStringW
 
 //sys  expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) = kernel32.ExpandEnvironmentStringsW
index f4bb1b35a542d3979d7028cf70fbba3dbc253e9c..71d4e15bab16ea5492ab0c979d7357394ded8039 100644 (file)
@@ -108,10 +108,65 @@ func (k Key) GetStringValue(name string) (val string, valtype uint32, err error)
        if len(data) == 0 {
                return "", typ, nil
        }
-       u := (*[1 << 10]uint16)(unsafe.Pointer(&data[0]))[:]
+       u := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:]
        return syscall.UTF16ToString(u), typ, nil
 }
 
+// GetMUIStringValue retrieves the localized string value for
+// the specified value name associated with an open key k.
+// If the value name doesn't exist or the localized string value
+// can't be resolved, GetMUIStringValue returns ErrNotExist.
+// GetMUIStringValue panics if the system doesn't support
+// regLoadMUIString; use LoadRegLoadMUIString to check if
+// regLoadMUIString is supported before calling this function.
+func (k Key) GetMUIStringValue(name string) (string, error) {
+       pname, err := syscall.UTF16PtrFromString(name)
+       if err != nil {
+               return "", err
+       }
+
+       buf := make([]uint16, 1024)
+       var buflen uint32
+       var pdir *uint16
+
+       err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
+       if err == syscall.ERROR_FILE_NOT_FOUND { // Try fallback path
+
+               // Try to resolve the string value using the system directory as
+               // a DLL search path; this assumes the string value is of the form
+               // @[path]\dllname,-strID but with no path given, e.g. @tzres.dll,-320.
+
+               // This approach works with tzres.dll but may have to be revised
+               // in the future to allow callers to provide custom search paths.
+
+               var s string
+               s, err = ExpandString("%SystemRoot%\\system32\\")
+               if err != nil {
+                       return "", err
+               }
+               pdir, err = syscall.UTF16PtrFromString(s)
+               if err != nil {
+                       return "", err
+               }
+
+               err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
+       }
+
+       for err == syscall.ERROR_MORE_DATA { // Grow buffer if needed
+               if buflen <= uint32(len(buf)) {
+                       break // Buffer not growing, assume race; break
+               }
+               buf = make([]uint16, buflen)
+               err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
+       }
+
+       if err != nil {
+               return "", err
+       }
+
+       return syscall.UTF16ToString(buf), nil
+}
+
 // ExpandString expands environment-variable strings and replaces
 // them with the values defined for the current user.
 // Use ExpandString to expand EXPAND_SZ strings.
@@ -130,7 +185,7 @@ func ExpandString(value string) (string, error) {
                        return "", err
                }
                if n <= uint32(len(r)) {
-                       u := (*[1 << 15]uint16)(unsafe.Pointer(&r[0]))[:]
+                       u := (*[1 << 29]uint16)(unsafe.Pointer(&r[0]))[:]
                        return syscall.UTF16ToString(u), nil
                }
                r = make([]uint16, n)
@@ -153,7 +208,7 @@ func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err err
        if len(data) == 0 {
                return nil, typ, nil
        }
-       p := (*[1 << 24]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2]
+       p := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2]
        if len(p) == 0 {
                return nil, typ, nil
        }
@@ -241,7 +296,7 @@ func (k Key) setStringValue(name string, valtype uint32, value string) error {
        if err != nil {
                return err
        }
-       buf := (*[1 << 10]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
+       buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
        return k.setValue(name, valtype, buf)
 }
 
@@ -271,7 +326,7 @@ func (k Key) SetStringsValue(name string, value []string) error {
                ss += s + "\x00"
        }
        v := utf16.Encode([]rune(ss + "\x00"))
-       buf := (*[1 << 10]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
+       buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
        return k.setValue(name, MULTI_SZ, buf)
 }
 
index 2b3de633c9bc5f24cd51f4b0cf57d35e026cd808..9c17675a249a9c0e47eeb931cda9caba5b6b2cd2 100644 (file)
@@ -16,6 +16,7 @@ var (
        procRegSetValueExW            = modadvapi32.NewProc("RegSetValueExW")
        procRegEnumValueW             = modadvapi32.NewProc("RegEnumValueW")
        procRegDeleteValueW           = modadvapi32.NewProc("RegDeleteValueW")
+       procRegLoadMUIStringW         = modadvapi32.NewProc("RegLoadMUIStringW")
        procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW")
 )
 
@@ -59,6 +60,14 @@ func regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) {
        return
 }
 
+func regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) {
+       r0, _, _ := syscall.Syscall9(procRegLoadMUIStringW.Addr(), 7, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(unsafe.Pointer(buflenCopied)), uintptr(flags), uintptr(unsafe.Pointer(dir)), 0, 0)
+       if r0 != 0 {
+               regerrno = syscall.Errno(r0)
+       }
+       return
+}
+
 func expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) {
        r0, _, e1 := syscall.Syscall(procExpandEnvironmentStringsW.Addr(), 3, uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(dst)), uintptr(size))
        n = uint32(r0)
index dc8a91626dec629a6ab8d776208d8d0a905cca0f..165e8945ec37a547d93c15992219eac2de0c5e4e 100644 (file)
@@ -10,7 +10,17 @@ import "syscall"
 
 const GAA_FLAG_INCLUDE_PREFIX = 0x00000010
 
-const IF_TYPE_SOFTWARE_LOOPBACK = 24
+const (
+       IF_TYPE_OTHER              = 1
+       IF_TYPE_ETHERNET_CSMACD    = 6
+       IF_TYPE_ISO88025_TOKENRING = 9
+       IF_TYPE_PPP                = 23
+       IF_TYPE_SOFTWARE_LOOPBACK  = 24
+       IF_TYPE_ATM                = 37
+       IF_TYPE_IEEE80211          = 71
+       IF_TYPE_TUNNEL             = 131
+       IF_TYPE_IEEE1394           = 144
+)
 
 type SocketAddress struct {
        Sockaddr       *syscall.RawSockaddrAny
@@ -94,7 +104,7 @@ const (
        IfOperStatusLowerLayerDown = 7
 )
 
-//sys GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizeOfPointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses
+//sys  GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses
 //sys  GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
 //sys  MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW
 
@@ -128,3 +138,6 @@ func Rename(oldpath, newpath string) error {
        }
        return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING)
 }
+
+//sys  GetACP() (acp uint32) = kernel32.GetACP
+//sys  MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar
index c6f607a46ad71480279125a13af17e3c98d2c7d4..de41786c76e77950ffa5940c9023fc93b5b8e8a7 100644 (file)
@@ -14,10 +14,12 @@ var (
        procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
        procGetComputerNameExW   = modkernel32.NewProc("GetComputerNameExW")
        procMoveFileExW          = modkernel32.NewProc("MoveFileExW")
+       procGetACP               = modkernel32.NewProc("GetACP")
+       procMultiByteToWideChar  = modkernel32.NewProc("MultiByteToWideChar")
 )
 
-func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizeOfPointer *uint32) (errcode error) {
-       r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizeOfPointer)), 0)
+func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) {
+       r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)), 0)
        if r0 != 0 {
                errcode = syscall.Errno(r0)
        }
@@ -47,3 +49,22 @@ func MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) {
        }
        return
 }
+
+func GetACP() (acp uint32) {
+       r0, _, _ := syscall.Syscall(procGetACP.Addr(), 0, 0, 0, 0)
+       acp = uint32(r0)
+       return
+}
+
+func MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) {
+       r0, _, e1 := syscall.Syscall6(procMultiByteToWideChar.Addr(), 6, uintptr(codePage), uintptr(dwFlags), uintptr(unsafe.Pointer(str)), uintptr(nstr), uintptr(unsafe.Pointer(wchar)), uintptr(nwchar))
+       nwrite = int32(r0)
+       if nwrite == 0 {
+               if e1 != 0 {
+                       err = error(e1)
+               } else {
+                       err = syscall.EINVAL
+               }
+       }
+       return
+}
index 1eb39ddd76ce1d7d7c7616ee91027b673b91ba8c..11f9aba616260eb4947e1b299604f5aa8700e4e2 100644 (file)
@@ -479,7 +479,7 @@ func postProcessTrace(events []*Event) error {
                        p.g = ev.G
                        if g.evCreate != nil {
                                // +1 because symbolizer expects return pc.
-                               ev.Stk = []*Frame{&Frame{PC: g.evCreate.Args[1] + 1}}
+                               ev.Stk = []*Frame{{PC: g.evCreate.Args[1] + 1}}
                                g.evCreate = nil
                        }
 
index 0eeb3e600e44848a8ffdf4c69c46d62ad1246508..fecefc4053a0d76437fe5b19b6d4911288fc360a 100644 (file)
@@ -24,7 +24,7 @@ func TestCorruptedInputs(t *testing.T) {
        for _, data := range tests {
                events, err := Parse(strings.NewReader(data))
                if err == nil || events != nil {
-                       t.Fatalf("no error on input: %q\n", t)
+                       t.Fatalf("no error on input: %q\n", data)
                }
        }
 }
diff --git a/libgo/go/io/example_test.go b/libgo/go/io/example_test.go
new file mode 100644 (file)
index 0000000..412dfb3
--- /dev/null
@@ -0,0 +1,223 @@
+// Copyright 2015 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 io_test
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "io/ioutil"
+       "log"
+       "os"
+       "strings"
+)
+
+func ExampleCopy() {
+       r := strings.NewReader("some io.Reader stream to be read\n")
+
+       if _, err := io.Copy(os.Stdout, r); err != nil {
+               log.Fatal(err)
+       }
+
+       // Output:
+       // some io.Reader stream to be read
+}
+
+func ExampleCopyBuffer() {
+       r1 := strings.NewReader("first reader\n")
+       r2 := strings.NewReader("second reader\n")
+       buf := make([]byte, 8)
+
+       // buf is used here...
+       if _, err := io.CopyBuffer(os.Stdout, r1, buf); err != nil {
+               log.Fatal(err)
+       }
+
+       // ... reused here also. No need to allocate an extra buffer.
+       if _, err := io.CopyBuffer(os.Stdout, r2, buf); err != nil {
+               log.Fatal(err)
+       }
+
+       // Output:
+       // first reader
+       // second reader
+}
+
+func ExampleCopyN() {
+       r := strings.NewReader("some io.Reader stream to be read")
+
+       if _, err := io.CopyN(os.Stdout, r, 5); err != nil {
+               log.Fatal(err)
+       }
+
+       // Output:
+       // some
+}
+
+func ExampleReadAtLeast() {
+       r := strings.NewReader("some io.Reader stream to be read\n")
+
+       buf := make([]byte, 33)
+       if _, err := io.ReadAtLeast(r, buf, 4); err != nil {
+               log.Fatal(err)
+       }
+       fmt.Printf("%s\n", buf)
+
+       // buffer smaller than minimal read size.
+       shortBuf := make([]byte, 3)
+       if _, err := io.ReadAtLeast(r, shortBuf, 4); err != nil {
+               fmt.Println("error:", err)
+       }
+
+       // minimal read size bigger than io.Reader stream
+       longBuf := make([]byte, 64)
+       if _, err := io.ReadAtLeast(r, longBuf, 64); err != nil {
+               fmt.Println("error:", err)
+       }
+
+       // Output:
+       // some io.Reader stream to be read
+       //
+       // error: short buffer
+       // error: EOF
+}
+
+func ExampleReadFull() {
+       r := strings.NewReader("some io.Reader stream to be read\n")
+
+       buf := make([]byte, 4)
+       if _, err := io.ReadFull(r, buf); err != nil {
+               log.Fatal(err)
+       }
+       fmt.Printf("%s\n", buf)
+
+       // minimal read size bigger than io.Reader stream
+       longBuf := make([]byte, 64)
+       if _, err := io.ReadFull(r, longBuf); err != nil {
+               fmt.Println("error:", err)
+       }
+
+       // Output:
+       // some
+       // error: unexpected EOF
+}
+
+func ExampleWriteString() {
+       io.WriteString(os.Stdout, "Hello World")
+
+       // Output: Hello World
+}
+
+func ExampleLimitReader() {
+       r := strings.NewReader("some io.Reader stream to be read\n")
+       lr := io.LimitReader(r, 4)
+
+       if _, err := io.Copy(os.Stdout, lr); err != nil {
+               log.Fatal(err)
+       }
+
+       // Output:
+       // some
+}
+
+func ExampleMultiReader() {
+       r1 := strings.NewReader("first reader ")
+       r2 := strings.NewReader("second reader ")
+       r3 := strings.NewReader("third reader\n")
+       r := io.MultiReader(r1, r2, r3)
+
+       if _, err := io.Copy(os.Stdout, r); err != nil {
+               log.Fatal(err)
+       }
+
+       // Output:
+       // first reader second reader third reader
+}
+
+func ExampleTeeReader() {
+       r := strings.NewReader("some io.Reader stream to be read\n")
+       var buf bytes.Buffer
+       tee := io.TeeReader(r, &buf)
+
+       printall := func(r io.Reader) {
+               b, err := ioutil.ReadAll(r)
+               if err != nil {
+                       log.Fatal(err)
+               }
+
+               fmt.Printf("%s", b)
+       }
+
+       printall(tee)
+       printall(&buf)
+
+       // Output:
+       // some io.Reader stream to be read
+       // some io.Reader stream to be read
+}
+
+func ExampleSectionReader() {
+       r := strings.NewReader("some io.Reader stream to be read\n")
+       s := io.NewSectionReader(r, 5, 17)
+
+       if _, err := io.Copy(os.Stdout, s); err != nil {
+               log.Fatal(err)
+       }
+
+       // Output:
+       // io.Reader stream
+}
+
+func ExampleSectionReader_ReadAt() {
+       r := strings.NewReader("some io.Reader stream to be read\n")
+       s := io.NewSectionReader(r, 5, 16)
+
+       buf := make([]byte, 6)
+       if _, err := s.ReadAt(buf, 10); err != nil {
+               log.Fatal(err)
+       }
+
+       fmt.Printf("%s\n", buf)
+
+       // Output:
+       // stream
+}
+
+func ExampleSectionReader_Seek() {
+       r := strings.NewReader("some io.Reader stream to be read\n")
+       s := io.NewSectionReader(r, 5, 16)
+
+       if _, err := s.Seek(10, 0); err != nil {
+               log.Fatal(err)
+       }
+
+       buf := make([]byte, 6)
+       if _, err := s.Read(buf); err != nil {
+               log.Fatal(err)
+       }
+
+       fmt.Printf("%s\n", buf)
+
+       // Output:
+       // stream
+}
+
+func ExampleMultiWriter() {
+       r := strings.NewReader("some io.Reader stream to be read\n")
+
+       var buf1, buf2 bytes.Buffer
+       w := io.MultiWriter(&buf1, &buf2)
+
+       if _, err := io.Copy(w, r); err != nil {
+               log.Fatal(err)
+       }
+
+       fmt.Print(buf1.String())
+       fmt.Print(buf2.String())
+
+       // Output:
+       // some io.Reader stream to be read
+       // some io.Reader stream to be read
+}
index 8851eaf00ab38368c10e9c0ebe1e890add3b463f..8e7855c665f08d1dbfa5059fe00556252dd943d0 100644 (file)
@@ -95,14 +95,14 @@ type Closer interface {
 // Seeker is the interface that wraps the basic Seek method.
 //
 // Seek sets the offset for the next Read or Write to offset,
-// interpreted according to whence: 0 means relative to the origin of
+// interpreted according to whence: 0 means relative to the start of
 // the file, 1 means relative to the current offset, and 2 means
-// relative to the end.  Seek returns the new offset and an error, if
-// any.
+// relative to the end. Seek returns the new offset relative to the
+// start of the file and an error, if any.
 //
-// Seeking to a negative offset is an error. Seeking to any positive
-// offset is legal, but the behavior of subsequent I/O operations on
-// the underlying object is implementation-dependent.
+// Seeking to an offset before the start of the file is an error.
+// Seeking to any positive offset is legal, but the behavior of subsequent
+// I/O operations on the underlying object is implementation-dependent.
 type Seeker interface {
        Seek(offset int64, whence int) (int64, error)
 }
@@ -225,7 +225,6 @@ type WriterAt interface {
 // ByteReader is the interface that wraps the ReadByte method.
 //
 // ReadByte reads and returns the next byte from the input.
-// If no byte is available, err will be set.
 type ByteReader interface {
        ReadByte() (c byte, err error)
 }
diff --git a/libgo/go/io/ioutil/example_test.go b/libgo/go/io/ioutil/example_test.go
new file mode 100644 (file)
index 0000000..74a7791
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright 2015 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 ignore
+
+package ioutil_test
+
+import (
+       "fmt"
+       "io/ioutil"
+       "log"
+       "os"
+       "path/filepath"
+       "strings"
+)
+
+func ExampleReadAll() {
+       r := strings.NewReader("Go is a general-purpose language designed with systems programming in mind.")
+
+       b, err := ioutil.ReadAll(r)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       fmt.Printf("%s", b)
+
+       // Output:
+       // Go is a general-purpose language designed with systems programming in mind.
+}
+
+func ExampleReadDir() {
+       files, err := ioutil.ReadDir(".")
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       for _, file := range files {
+               fmt.Println(file.Name())
+       }
+}
+
+func ExampleTempDir() {
+       content := []byte("temporary file's content")
+       dir, err := ioutil.TempDir("", "example")
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       defer os.RemoveAll(dir) // clean up
+
+       tmpfn := filepath.Join(dir, "tmpfile")
+       if err := ioutil.WriteFile(tmpfn, content, 0666); err != nil {
+               log.Fatal(err)
+       }
+}
+
+func ExampleTempFile() {
+       content := []byte("temporary file's content")
+       tmpfile, err := ioutil.TempFile("", "example")
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       defer os.Remove(tmpfile.Name()) // clean up
+
+       if _, err := tmpfile.Write(content); err != nil {
+               log.Fatal(err)
+       }
+       if err := tmpfile.Close(); err != nil {
+               log.Fatal(err)
+       }
+}
index 909a8156326735dbfaca50dca573dcf38b8facfa..e90a33f99b08f6f9b27fa351483fd4ccf4dca80d 100644 (file)
@@ -96,7 +96,7 @@ func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
 func (f byName) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }
 
 // ReadDir reads the directory named by dirname and returns
-// a list of sorted directory entries.
+// a list of directory entries sorted by filename.
 func ReadDir(dirname string) ([]os.FileInfo, error) {
        f, err := os.Open(dirname)
        if err != nil {
index e26cc53e9eeb7cc8477a00247b177ffd9cea3a36..16860aa361f13ab62f6afc33857a2d308a7ac7c5 100644 (file)
@@ -52,6 +52,30 @@ func (t *multiWriter) Write(p []byte) (n int, err error) {
        return len(p), nil
 }
 
+var _ stringWriter = (*multiWriter)(nil)
+
+func (t *multiWriter) WriteString(s string) (n int, err error) {
+       var p []byte // lazily initialized if/when needed
+       for _, w := range t.writers {
+               if sw, ok := w.(stringWriter); ok {
+                       n, err = sw.WriteString(s)
+               } else {
+                       if p == nil {
+                               p = []byte(s)
+                       }
+                       n, err = w.Write(p)
+               }
+               if err != nil {
+                       return
+               }
+               if n != len(s) {
+                       err = ErrShortWrite
+                       return
+               }
+       }
+       return len(s), nil
+}
+
 // 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 {
index 56c6769a9eb598cc8e1671c88848eb5eb2f85245..c5d1b9530eac60e380e0d32dfe76581c7fec83c2 100644 (file)
@@ -62,8 +62,60 @@ func TestMultiReader(t *testing.T) {
 }
 
 func TestMultiWriter(t *testing.T) {
-       sha1 := sha1.New()
        sink := new(bytes.Buffer)
+       // Hide bytes.Buffer's WriteString method:
+       testMultiWriter(t, struct {
+               Writer
+               fmt.Stringer
+       }{sink, sink})
+}
+
+func TestMultiWriter_String(t *testing.T) {
+       testMultiWriter(t, new(bytes.Buffer))
+}
+
+// test that a multiWriter.WriteString calls results in at most 1 allocation,
+// even if multiple targets don't support WriteString.
+func TestMultiWriter_WriteStringSingleAlloc(t *testing.T) {
+       t.Skip("skipping on gccgo until we have escape analysis")
+       var sink1, sink2 bytes.Buffer
+       type simpleWriter struct { // hide bytes.Buffer's WriteString
+               Writer
+       }
+       mw := MultiWriter(simpleWriter{&sink1}, simpleWriter{&sink2})
+       allocs := int(testing.AllocsPerRun(1000, func() {
+               WriteString(mw, "foo")
+       }))
+       if allocs != 1 {
+               t.Errorf("num allocations = %d; want 1", allocs)
+       }
+}
+
+type writeStringChecker struct{ called bool }
+
+func (c *writeStringChecker) WriteString(s string) (n int, err error) {
+       c.called = true
+       return len(s), nil
+}
+
+func (c *writeStringChecker) Write(p []byte) (n int, err error) {
+       return len(p), nil
+}
+
+func TestMultiWriter_StringCheckCall(t *testing.T) {
+       var c writeStringChecker
+       mw := MultiWriter(&c)
+       WriteString(mw, "foo")
+       if !c.called {
+               t.Error("did not see WriteString call to writeStringChecker")
+       }
+}
+
+func testMultiWriter(t *testing.T, sink interface {
+       Writer
+       fmt.Stringer
+}) {
+       sha1 := sha1.New()
        mw := MultiWriter(sha1, sink)
 
        sourceString := "My input text."
index 54e76edb34bab539b896978df74f9ea7c88c3e4a..dfcc2dde34fa65ead43bc8b9a6d80f0741d5bc9e 100644 (file)
@@ -9,10 +9,18 @@
 // Only one call to Dial is necessary. On write failures,
 // the syslog client will attempt to reconnect to the server
 // and write again.
+//
+// The syslog package is frozen and not accepting new features.
+// Some external packages provide more functionality. See:
+//
+//   https://godoc.org/?q=syslog
 package syslog
 
-// BUG(brainman): This package is not implemented on Windows yet.
+// BUG(brainman): This package is not implemented on Windows. As the
+// syslog package is frozen, Windows users are encouraged to
+// use a package outside of the standard library. For background,
+// see https://golang.org/issue/1108.
 
-// BUG(akumar): This package is not implemented on Plan 9 yet.
+// BUG(akumar): This package is not implemented on Plan 9.
 
-// BUG(minux): This package is not implemented on NaCl (Native Client) yet.
+// BUG(minux): This package is not implemented on NaCl (Native Client).
index 85aec536abef258843d5c7f6a999af1ed1699585..52363f9f7c2c1bf36302df0c9efa4a10a55af1d0 100644 (file)
@@ -47,6 +47,22 @@ func runPktSyslog(c net.PacketConn, done chan<- string) {
 
 var crashy = false
 
+func testableNetwork(network string) bool {
+       switch network {
+       case "unix", "unixgram":
+               switch runtime.GOOS {
+               case "darwin":
+                       switch runtime.GOARCH {
+                       case "arm", "arm64":
+                               return false
+                       }
+               case "android":
+                       return false
+               }
+       }
+       return true
+}
+
 func runStreamSyslog(l net.Listener, done chan<- string, wg *sync.WaitGroup) {
        for {
                var c net.Conn
@@ -119,12 +135,10 @@ func startServer(n, la string, done chan<- string) (addr string, sock io.Closer,
 
 func TestWithSimulated(t *testing.T) {
        msg := "Test 123"
-       transport := []string{"unix", "unixgram", "udp", "tcp"}
-
-       if runtime.GOOS == "darwin" {
-               switch runtime.GOARCH {
-               case "arm", "arm64":
-                       transport = []string{"udp", "tcp"}
+       var transport []string
+       for _, n := range []string{"unix", "unixgram", "udp", "tcp"} {
+               if testableNetwork(n) {
+                       transport = append(transport, n)
                }
        }
 
@@ -150,14 +164,11 @@ func TestWithSimulated(t *testing.T) {
 }
 
 func TestFlap(t *testing.T) {
-       if runtime.GOOS == "darwin" {
-               switch runtime.GOARCH {
-               case "arm", "arm64":
-                       t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
-               }
+       net := "unix"
+       if !testableNetwork(net) {
+               t.Skipf("skipping on %s/%s; 'unix' is not supported", runtime.GOOS, runtime.GOARCH)
        }
 
-       net := "unix"
        done := make(chan string)
        addr, sock, srvWG := startServer(net, "", done)
        defer srvWG.Wait()
@@ -321,10 +332,10 @@ func TestConcurrentReconnect(t *testing.T) {
        const N = 10
        const M = 100
        net := "unix"
-       if runtime.GOOS == "darwin" {
-               switch runtime.GOARCH {
-               case "arm", "arm64":
-                       net = "tcp"
+       if !testableNetwork(net) {
+               net = "tcp"
+               if !testableNetwork(net) {
+                       t.Skipf("skipping on %s/%s; neither 'unix' or 'tcp' is supported", runtime.GOOS, runtime.GOARCH)
                }
        }
        done := make(chan string, N*M)
index 433d0f727376008958c78cceb574c3178509f2ad..1b7c7c1820c56e603749be4a21d1e7207dc4b8ae 100644 (file)
@@ -18,10 +18,13 @@ func Abs(x float64) float64 {
 }
 
 func abs(x float64) float64 {
-       switch {
-       case x < 0:
+       // TODO: once golang.org/issue/13095 is fixed, change this to:
+       // return Float64frombits(Float64bits(x) &^ (1 << 63))
+       // But for now, this generates better code and can also be inlined:
+       if x < 0 {
                return -x
-       case x == 0:
+       }
+       if x == 0 {
                return 0 // return correctly abs(-0)
        }
        return x
index e18e45e020228d95d77e779f5f2a8d9e9e54cd6c..968a7b18372a0e2fbfd825f0950ea625e6fe7386 100644 (file)
@@ -234,6 +234,18 @@ var expm1 = []float64{
        1.842068661871398836913874273e-02,
        -8.3193870863553801814961137573e-02,
 }
+var expm1Large = []float64{
+       4.2031418113550844e+21,
+       4.0690789717473863e+33,
+       -0.9372627915981363e+00,
+       -1.0,
+       7.077694784145933e+41,
+       5.117936223839153e+12,
+       5.124137759001189e+22,
+       7.03546003972584e+11,
+       8.456921800389698e+07,
+       -1.0,
+}
 var exp2 = []float64{
        3.1537839463286288034313104e+01,
        2.1361549283756232296144849e+02,
@@ -447,7 +459,7 @@ var log2 = []float64{
 var modf = [][2]float64{
        {4.0000000000000000e+00, 9.7901192488367350108546816e-01},
        {7.0000000000000000e+00, 7.3887247457810456552351752e-01},
-       {0.0000000000000000e+00, -2.7688005719200159404635997e-01},
+       {Copysign(0, -1), -2.7688005719200159404635997e-01},
        {-5.0000000000000000e+00, -1.060361827107492160848778e-02},
        {9.0000000000000000e+00, 6.3629370719841737980004837e-01},
        {2.0000000000000000e+00, 9.2637723924396464525443662e-01},
@@ -1356,12 +1368,14 @@ var log1pSC = []float64{
 
 var vfmodfSC = []float64{
        Inf(-1),
+       Copysign(0, -1),
        Inf(1),
        NaN(),
 }
 var modfSC = [][2]float64{
        {Inf(-1), NaN()}, // [2]float64{Copysign(0, -1), Inf(-1)},
-       {Inf(1), NaN()},  // [2]float64{0, Inf(1)},
+       {Copysign(0, -1), Copysign(0, -1)},
+       {Inf(1), NaN()}, // [2]float64{0, Inf(1)},
        {NaN(), NaN()},
 }
 
@@ -1609,6 +1623,7 @@ var vfsqrtSC = []float64{
        0,
        Inf(1),
        NaN(),
+       Float64frombits(2), // subnormal; see https://golang.org/issue/13013
 }
 var sqrtSC = []float64{
        NaN(),
@@ -1617,6 +1632,7 @@ var sqrtSC = []float64{
        0,
        Inf(1),
        NaN(),
+       3.1434555694052576e-162,
 }
 
 var vftanhSC = []float64{
@@ -1983,6 +1999,12 @@ func TestExpm1(t *testing.T) {
                        t.Errorf("Expm1(%g) = %g, want %g", a, f, expm1[i])
                }
        }
+       for i := 0; i < len(vf); i++ {
+               a := vf[i] * 10
+               if f := Expm1(a); !close(expm1Large[i], f) {
+                       t.Errorf("Expm1(%g) = %g, want %g", a, f, expm1Large[i])
+               }
+       }
        for i := 0; i < len(vfexpm1SC); i++ {
                if f := Expm1(vfexpm1SC[i]); !alike(expm1SC[i], f) {
                        t.Errorf("Expm1(%g) = %g, want %g", vfexpm1SC[i], f, expm1SC[i])
index 2595e5f8c121fb096a25977a21f1dbd646f525b3..2c0c9daebc18e3f0258530456482f8be73b6895d 100644 (file)
@@ -20,7 +20,7 @@
 package big
 
 // A decimal represents an unsigned floating-point number in decimal representation.
-// The value of a non-zero decimal x is x.mant * 10 ** x.exp with 0.5 <= x.mant < 1,
+// The value of a non-zero decimal d is d.mant * 10**d.exp with 0.5 <= d.mant < 1,
 // with the most-significant mantissa digit at index 0. For the zero decimal, the
 // mantissa length and exponent are 0.
 // The zero value for decimal represents a ready-to-use 0.0.
@@ -29,6 +29,14 @@ type decimal struct {
        exp  int    // exponent
 }
 
+// at returns the i'th mantissa digit, starting with the most significant digit at 0.
+func (d *decimal) at(i int) byte {
+       if 0 <= i && i < len(d.mant) {
+               return d.mant[i]
+       }
+       return '0'
+}
+
 // Maximum shift amount that can be done in one pass without overflow.
 // A Word has _W bits and (1<<maxShift - 1)*10 + 9 must fit into Word.
 const maxShift = _W - 4
@@ -72,7 +80,7 @@ func (x *decimal) init(m nat, shift int) {
        }
 
        // Convert mantissa into decimal representation.
-       s := m.decimalString() // TODO(gri) avoid string conversion here
+       s := m.utoa(10)
        n := len(s)
        x.exp = n
        // Trim trailing zeros; instead the exponent is tracking
@@ -92,12 +100,6 @@ func (x *decimal) init(m nat, shift int) {
        }
 }
 
-// Possibly optimization: The current implementation of nat.string takes
-// a charset argument. When a right shift is needed, we could provide
-// "\x00\x01...\x09" instead of "012..9" (as in nat.decimalString) and
-// avoid the repeated +'0' and -'0' operations in decimal.shr (and do a
-// single +'0' pass at the end).
-
 // shr implements x >> s, for s <= maxShift.
 func shr(x *decimal, s uint) {
        // Division by 1<<s using shift-and-subtract algorithm.
index 81e022a47dd60848e06cf8b802ce7e8979520f9e..15bdb181e725742bca198443dc720aaa3f06a0e0 100644 (file)
@@ -104,3 +104,13 @@ func TestDecimalRounding(t *testing.T) {
                }
        }
 }
+
+func BenchmarkDecimalConversion(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               for shift := -100; shift <= +100; shift++ {
+                       var d decimal
+                       d.init(natOne, shift)
+                       d.String()
+               }
+       }
+}
diff --git a/libgo/go/math/big/doc.go b/libgo/go/math/big/doc.go
new file mode 100644 (file)
index 0000000..a3c2375
--- /dev/null
@@ -0,0 +1,99 @@
+// 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 big implements arbitrary-precision arithmetic (big numbers).
+The following numeric types are supported:
+
+       Int    signed integers
+       Rat    rational numbers
+       Float  floating-point numbers
+
+The zero value for an Int, Rat, or Float correspond to 0. Thus, new
+values can be declared in the usual ways and denote 0 without further
+initialization:
+
+       var x Int        // &x is an *Int of value 0
+       var r = &Rat{}   // r is a *Rat of value 0
+       y := new(Float)  // y is a *Float of value 0
+
+Alternatively, new values can be allocated and initialized with factory
+functions of the form:
+
+       func NewT(v V) *T
+
+For instance, NewInt(x) returns an *Int set to the value of the int64
+argument x, NewRat(a, b) returns a *Rat set to the fraction a/b where
+a and b are int64 values, and NewFloat(f) returns a *Float initialized
+to the float64 argument f. More flexibility is provided with explicit
+setters, for instance:
+
+       var z1 Int
+       z1.SetUint64(123)                 // z1 := 123
+       z2 := new(Rat).SetFloat64(1.2)    // z2 := 6/5
+       z3 := new(Float).SetInt(z1)       // z3 := 123.0
+
+Setters, numeric operations and predicates are represented as methods of
+the form:
+
+       func (z *T) SetV(v V) *T          // z = v
+       func (z *T) Unary(x *T) *T        // z = unary x
+       func (z *T) Binary(x, y *T) *T    // z = x binary y
+       func (x *T) Pred() P              // p = pred(x)
+
+with T one of Int, Rat, or Float. For unary and binary operations, the
+result is the receiver (usually named z in that case; see below); if it
+is one of the operands x or y it may be safely overwritten (and its memory
+reused).
+
+Arithmetic expressions are typically written as a sequence of individual
+method calls, with each call corresponding to an operation. The receiver
+denotes the result and the method arguments are the operation's operands.
+For instance, given three *Int values a, b and c, the invocation
+
+       c.Add(a, b)
+
+computes the sum a + b and stores the result in c, overwriting whatever
+value was held in c before. Unless specified otherwise, operations permit
+aliasing of parameters, so it is perfectly ok to write
+
+       sum.Add(sum, x)
+
+to accumulate values x in a sum.
+
+(By always passing in a result value via the receiver, memory use can be
+much better controlled. Instead of having to allocate new memory for each
+result, an operation can reuse the space allocated for the result value,
+and overwrite that value with the new result in the process.)
+
+Notational convention: Incoming method parameters (including the receiver)
+are named consistently in the API to clarify their use. Incoming operands
+are usually named x, y, a, b, and so on, but never z. A parameter specifying
+the result is named z (typically the receiver).
+
+For instance, the arguments for (*Int).Add are named x and y, and because
+the receiver specifies the result destination, it is called z:
+
+       func (z *Int) Add(x, y *Int) *Int
+
+Methods of this form typically return the incoming receiver as well, to
+enable simple call chaining.
+
+Methods which don't require a result value to be passed in (for instance,
+Int.Sign), simply return the result. In this case, the receiver is typically
+the first operand, named x:
+
+       func (x *Int) Sign() int
+
+Various methods support conversions between strings and corresponding
+numeric values, and vice versa: *Int, *Rat, and *Float values implement
+the Stringer interface for a (default) string representation of the value,
+but also provide SetString methods to initialize a value from a string in
+a variety of supported formats (see the respective SetString documentation).
+
+Finally, *Int, *Rat, and *Float satisfy the fmt package's Scanner interface
+for scanning and (except for *Rat) the Formatter interface for formatted
+printing.
+*/
+package big
diff --git a/libgo/go/math/big/example_rat_test.go b/libgo/go/math/big/example_rat_test.go
new file mode 100644 (file)
index 0000000..f3127bb
--- /dev/null
@@ -0,0 +1,67 @@
+// Copyright 2015 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 ignore
+
+package big_test
+
+import (
+       "fmt"
+       "math/big"
+)
+
+// Use the classic continued fraction for e
+//     e = [1; 0, 1, 1, 2, 1, 1, ... 2n, 1, 1, ...]
+// i.e., for the nth term, use
+//     1          if   n mod 3 != 1
+//  (n-1)/3 * 2   if   n mod 3 == 1
+func recur(n, lim int64) *big.Rat {
+       term := new(big.Rat)
+       if n%3 != 1 {
+               term.SetInt64(1)
+       } else {
+               term.SetInt64((n - 1) / 3 * 2)
+       }
+
+       if n > lim {
+               return term
+       }
+
+       // Directly initialize frac as the fractional
+       // inverse of the result of recur.
+       frac := new(big.Rat).Inv(recur(n+1, lim))
+
+       return term.Add(term, frac)
+}
+
+// This example demonstrates how to use big.Rat to compute the
+// first 15 terms in the sequence of rational convergents for
+// the constant e (base of natural logarithm).
+func Example_eConvergents() {
+       for i := 1; i <= 15; i++ {
+               r := recur(0, int64(i))
+
+               // Print r both as a fraction and as a floating-point number.
+               // Since big.Rat implements fmt.Formatter, we can use %-13s to
+               // get a left-aligned string representation of the fraction.
+               fmt.Printf("%-13s = %s\n", r, r.FloatString(8))
+       }
+
+       // Output:
+       // 2/1           = 2.00000000
+       // 3/1           = 3.00000000
+       // 8/3           = 2.66666667
+       // 11/4          = 2.75000000
+       // 19/7          = 2.71428571
+       // 87/32         = 2.71875000
+       // 106/39        = 2.71794872
+       // 193/71        = 2.71830986
+       // 1264/465      = 2.71827957
+       // 1457/536      = 2.71828358
+       // 2721/1001     = 2.71828172
+       // 23225/8544    = 2.71828184
+       // 25946/9545    = 2.71828182
+       // 49171/18089   = 2.71828183
+       // 517656/190435 = 2.71828183
+}
index d7aa8953c435ce45684a7d58770e1644028c2224..b1c748c9a54daea4ec257f7f1056af0d488b1517 100644 (file)
@@ -124,7 +124,7 @@ const (
 // rounding error is described by the Float's Accuracy.
 type RoundingMode byte
 
-// The following rounding modes are supported.
+// These constants define supported rounding modes.
 const (
        ToNearestEven RoundingMode = iota // == IEEE 754-2008 roundTiesToEven
        ToNearestAway                     // == IEEE 754-2008 roundTiesToAway
@@ -298,7 +298,7 @@ func (z *Float) setExpAndRound(exp int64, sbit uint) {
 // not require 0.5 <= |mant| < 1.0. Specifically:
 //
 //     mant := new(Float)
-//     new(Float).SetMantExp(mant, x.SetMantExp(mant)).Cmp(x).Eql() is true
+//     new(Float).SetMantExp(mant, x.MantExp(mant)).Cmp(x) == 0
 //
 // Special cases are:
 //
@@ -1123,7 +1123,7 @@ func (x *Float) Int(z *Int) (*Int, Accuracy) {
 
 // Rat returns the rational number corresponding to x;
 // or nil if x is an infinity.
-// The result is Exact is x is not an Inf.
+// The result is Exact if x is not an Inf.
 // If a non-nil *Rat argument z is provided, Rat stores
 // the result in z instead of allocating a new Rat.
 func (x *Float) Rat(z *Rat) (*Rat, Accuracy) {
@@ -1272,7 +1272,7 @@ func (z *Float) usub(x, y *Float) {
                ex = ey
        }
 
-       // operands may have cancelled each other out
+       // operands may have canceled each other out
        if len(z.mant) == 0 {
                z.acc = Exact
                z.form = zero
index 4a070ca64d4c835aedad131bb7abb2c6409a6466..37d5c06a6f33d6b132c665e7e17b55e28b6b6dea 100644 (file)
@@ -72,37 +72,46 @@ func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
        // ebase**exp. Finally, mantissa normalization (shift left) requires
        // a correcting multiplication by 2**(-shiftcount). Multiplications
        // are commutative, so we can apply them in any order as long as there
-       // is no loss of precision. We only have powers of 2 and 10; keep
-       // track via separate exponents exp2 and exp10.
+       // is no loss of precision. We only have powers of 2 and 10, and
+       // we split powers of 10 into the product of the same powers of
+       // 2 and 5. This reduces the size of the multiplication factor
+       // needed for base-10 exponents.
 
-       // normalize mantissa and get initial binary exponent
-       var exp2 = int64(len(z.mant))*_W - fnorm(z.mant)
+       // normalize mantissa and determine initial exponent contributions
+       exp2 := int64(len(z.mant))*_W - fnorm(z.mant)
+       exp5 := int64(0)
 
        // determine binary or decimal exponent contribution of decimal point
-       var exp10 int64
        if fcount < 0 {
                // The mantissa has a "decimal" point ddd.dddd; and
                // -fcount is the number of digits to the right of '.'.
                // Adjust relevant exponent accodingly.
+               d := int64(fcount)
                switch b {
-               case 16:
-                       fcount *= 4 // hexadecimal digits are 4 bits each
-                       fallthrough
+               case 10:
+                       exp5 = d
+                       fallthrough // 10**e == 5**e * 2**e
                case 2:
-                       exp2 += int64(fcount)
-               default: // b == 10
-                       exp10 = int64(fcount)
+                       exp2 += d
+               case 16:
+                       exp2 += d * 4 // hexadecimal digits are 4 bits each
+               default:
+                       panic("unexpected mantissa base")
                }
-               // we don't need fcount anymore
+               // fcount consumed - not needed anymore
        }
 
        // take actual exponent into account
-       if ebase == 2 {
+       switch ebase {
+       case 10:
+               exp5 += exp
+               fallthrough
+       case 2:
                exp2 += exp
-       } else { // ebase == 10
-               exp10 += exp
+       default:
+               panic("unexpected exponent base")
        }
-       // we don't need exp anymore
+       // exp consumed - not needed anymore
 
        // apply 2**exp2
        if MinExp <= exp2 && exp2 <= MaxExp {
@@ -115,49 +124,76 @@ func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
                return
        }
 
-       if exp10 == 0 {
-               // no decimal exponent to consider
+       if exp5 == 0 {
+               // no decimal exponent contribution
                z.round(0)
                return
        }
-       // exp10 != 0
+       // exp5 != 0
 
-       // apply 10**exp10
+       // apply 5**exp5
        p := new(Float).SetPrec(z.Prec() + 64) // use more bits for p -- TODO(gri) what is the right number?
-       if exp10 < 0 {
-               z.uquo(z, p.pow10(-exp10))
+       if exp5 < 0 {
+               z.Quo(z, p.pow5(uint64(-exp5)))
        } else {
-               z.umul(z, p.pow10(exp10))
+               z.Mul(z, p.pow5(uint64(exp5)))
        }
 
        return
 }
 
-// These powers of 10 can be represented exactly as a float64.
-var pow10tab = [...]float64{
-       1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
-       1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+// These powers of 5 fit into a uint64.
+//
+//     for p, q := uint64(0), uint64(1); p < q; p, q = q, q*5 {
+//             fmt.Println(q)
+//     }
+//
+var pow5tab = [...]uint64{
+       1,
+       5,
+       25,
+       125,
+       625,
+       3125,
+       15625,
+       78125,
+       390625,
+       1953125,
+       9765625,
+       48828125,
+       244140625,
+       1220703125,
+       6103515625,
+       30517578125,
+       152587890625,
+       762939453125,
+       3814697265625,
+       19073486328125,
+       95367431640625,
+       476837158203125,
+       2384185791015625,
+       11920928955078125,
+       59604644775390625,
+       298023223876953125,
+       1490116119384765625,
+       7450580596923828125,
 }
 
-// pow10 sets z to 10**n and returns z.
+// pow5 sets z to 5**n and returns z.
 // n must not be negative.
-func (z *Float) pow10(n int64) *Float {
-       if n < 0 {
-               panic("pow10 called with negative argument")
-       }
-
-       const m = int64(len(pow10tab) - 1)
+func (z *Float) pow5(n uint64) *Float {
+       const m = uint64(len(pow5tab) - 1)
        if n <= m {
-               return z.SetFloat64(pow10tab[n])
+               return z.SetUint64(pow5tab[n])
        }
        // n > m
 
-       z.SetFloat64(pow10tab[m])
+       z.SetUint64(pow5tab[m])
        n -= m
 
        // use more bits for f than for z
        // TODO(gri) what is the right number?
-       f := new(Float).SetPrec(z.Prec() + 64).SetInt64(10)
+       f := new(Float).SetPrec(z.Prec() + 64).SetUint64(5)
 
        for n > 0 {
                if n&1 != 0 {
index 4f239534a1403b903e56773d19225b5bd14eb02e..b6f999360825b8332f88cf90dba0cc6b01522b4b 100644 (file)
@@ -139,6 +139,8 @@ func TestFloatSetFloat64String(t *testing.T) {
        }
 }
 
+func fdiv(a, b float64) float64 { return a / b }
+
 const (
        below1e23 = 99999999999999974834176
        above1e23 = 100000000000000008388608
@@ -187,11 +189,11 @@ func TestFloat64Text(t *testing.T) {
                {1, 'e', 5, "1.00000e+00"},
                {1, 'f', 5, "1.00000"},
                {1, 'g', 5, "1"},
-               // {1, 'g', -1, "1"},
-               // {20, 'g', -1, "20"},
-               // {1234567.8, 'g', -1, "1.2345678e+06"},
-               // {200000, 'g', -1, "200000"},
-               // {2000000, 'g', -1, "2e+06"},
+               {1, 'g', -1, "1"},
+               {20, 'g', -1, "20"},
+               {1234567.8, 'g', -1, "1.2345678e+06"},
+               {200000, 'g', -1, "200000"},
+               {2000000, 'g', -1, "2e+06"},
 
                // g conversion and zero suppression
                {400, 'g', 2, "4e+02"},
@@ -207,22 +209,22 @@ func TestFloat64Text(t *testing.T) {
                {0, 'e', 5, "0.00000e+00"},
                {0, 'f', 5, "0.00000"},
                {0, 'g', 5, "0"},
-               // {0, 'g', -1, "0"},
+               {0, 'g', -1, "0"},
 
                {-1, 'e', 5, "-1.00000e+00"},
                {-1, 'f', 5, "-1.00000"},
                {-1, 'g', 5, "-1"},
-               // {-1, 'g', -1, "-1"},
+               {-1, 'g', -1, "-1"},
 
                {12, 'e', 5, "1.20000e+01"},
                {12, 'f', 5, "12.00000"},
                {12, 'g', 5, "12"},
-               // {12, 'g', -1, "12"},
+               {12, 'g', -1, "12"},
 
                {123456700, 'e', 5, "1.23457e+08"},
                {123456700, 'f', 5, "123456700.00000"},
                {123456700, 'g', 5, "1.2346e+08"},
-               // {123456700, 'g', -1, "1.234567e+08"},
+               {123456700, 'g', -1, "1.234567e+08"},
 
                {1.2345e6, 'e', 5, "1.23450e+06"},
                {1.2345e6, 'f', 5, "1234500.00000"},
@@ -232,36 +234,38 @@ func TestFloat64Text(t *testing.T) {
                {1e23, 'f', 17, "99999999999999991611392.00000000000000000"},
                {1e23, 'g', 17, "9.9999999999999992e+22"},
 
-               // {1e23, 'e', -1, "1e+23"},
-               // {1e23, 'f', -1, "100000000000000000000000"},
-               // {1e23, 'g', -1, "1e+23"},
+               {1e23, 'e', -1, "1e+23"},
+               {1e23, 'f', -1, "100000000000000000000000"},
+               {1e23, 'g', -1, "1e+23"},
 
                {below1e23, 'e', 17, "9.99999999999999748e+22"},
                {below1e23, 'f', 17, "99999999999999974834176.00000000000000000"},
                {below1e23, 'g', 17, "9.9999999999999975e+22"},
 
-               // {below1e23, 'e', -1, "9.999999999999997e+22"},
-               // {below1e23, 'f', -1, "99999999999999970000000"},
-               // {below1e23, 'g', -1, "9.999999999999997e+22"},
+               {below1e23, 'e', -1, "9.999999999999997e+22"},
+               {below1e23, 'f', -1, "99999999999999970000000"},
+               {below1e23, 'g', -1, "9.999999999999997e+22"},
 
                {above1e23, 'e', 17, "1.00000000000000008e+23"},
                {above1e23, 'f', 17, "100000000000000008388608.00000000000000000"},
-               // {above1e23, 'g', 17, "1.0000000000000001e+23"},
+               {above1e23, 'g', 17, "1.0000000000000001e+23"},
 
-               // {above1e23, 'e', -1, "1.0000000000000001e+23"},
-               // {above1e23, 'f', -1, "100000000000000010000000"},
-               // {above1e23, 'g', -1, "1.0000000000000001e+23"},
+               {above1e23, 'e', -1, "1.0000000000000001e+23"},
+               {above1e23, 'f', -1, "100000000000000010000000"},
+               {above1e23, 'g', -1, "1.0000000000000001e+23"},
 
-               // {fdiv(5e-304, 1e20), 'g', -1, "5e-324"},
-               // {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"},
+               {5e-304 / 1e20, 'g', -1, "5e-324"},
+               {-5e-304 / 1e20, 'g', -1, "-5e-324"},
+               {fdiv(5e-304, 1e20), 'g', -1, "5e-324"},   // avoid constant arithmetic
+               {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"}, // avoid constant arithmetic
 
-               // {32, 'g', -1, "32"},
-               // {32, 'g', 0, "3e+01"},
+               {32, 'g', -1, "32"},
+               {32, 'g', 0, "3e+01"},
 
-               // {100, 'x', -1, "%x"},
+               {100, 'x', -1, "%x"},
 
-               // {math.NaN(), 'g', -1, "NaN"},
-               // {-math.NaN(), 'g', -1, "NaN"},
+               // {math.NaN(), 'g', -1, "NaN"},  // Float doesn't support NaNs
+               // {-math.NaN(), 'g', -1, "NaN"}, // Float doesn't support NaNs
                {math.Inf(0), 'g', -1, "+Inf"},
                {math.Inf(-1), 'g', -1, "-Inf"},
                {-math.Inf(0), 'g', -1, "-Inf"},
@@ -279,18 +283,24 @@ func TestFloat64Text(t *testing.T) {
                {1.5, 'f', 0, "2"},
 
                // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
-               // {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"},
+               {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"},
                // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
-               // {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"},
+               {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"},
 
                // Issue 2625.
                {383260575764816448, 'f', 0, "383260575764816448"},
-               // {383260575764816448, 'g', -1, "3.8326057576481645e+17"},
+               {383260575764816448, 'g', -1, "3.8326057576481645e+17"},
        } {
-               f := new(Float).SetFloat64(test.x)
+               // The test cases are from the strconv package which tests float64 values.
+               // When formatting values with prec = -1 (shortest representation),
+               // the actually available mantissa precision matters.
+               // For denormalized values, that precision is < 53 (SetFloat64 default).
+               // Compute and set the actual precision explicitly.
+               f := new(Float).SetPrec(actualPrec(test.x)).SetFloat64(test.x)
                got := f.Text(test.format, test.prec)
                if got != test.want {
                        t.Errorf("%v: got %s; want %s", test, got, test.want)
+                       continue
                }
 
                if test.format == 'b' && test.x == 0 {
@@ -308,6 +318,15 @@ func TestFloat64Text(t *testing.T) {
        }
 }
 
+// actualPrec returns the number of actually used mantissa bits.
+func actualPrec(x float64) uint {
+       if bits := math.Float64bits(x); x != 0 && bits&(0x7ff<<52) == 0 {
+               // x is denormalized
+               return 64 - nlz64(bits&(1<<52-1))
+       }
+       return 53
+}
+
 func TestFloatText(t *testing.T) {
        for _, test := range []struct {
                x      string
@@ -367,9 +386,19 @@ func TestFloatText(t *testing.T) {
 
                // make sure "stupid" exponents don't stall the machine
                {"1e1000000", 64, 'p', 0, "0x.88b3a28a05eade3ap+3321929"},
-               {"1e1000000000", 64, 'p', 0, "0x.ecc5f45aa573d3p+1538481529"},
+               {"1e646456992", 64, 'p', 0, "0x.e883a0c5c8c7c42ap+2147483644"},
+               {"1e646456993", 64, 'p', 0, "+Inf"},
+               {"1e1000000000", 64, 'p', 0, "+Inf"},
                {"1e-1000000", 64, 'p', 0, "0x.efb4542cc8ca418ap-3321928"},
-               {"1e-1000000000", 64, 'p', 0, "0x.8a64dd983a4c7dabp-1538481528"},
+               {"1e-646456993", 64, 'p', 0, "0x.e17c8956983d9d59p-2147483647"},
+               {"1e-646456994", 64, 'p', 0, "0"},
+               {"1e-1000000000", 64, 'p', 0, "0"},
+
+               // minimum and maximum values
+               {"1p2147483646", 64, 'p', 0, "0x.8p+2147483647"},
+               {"0x.8p2147483647", 64, 'p', 0, "0x.8p+2147483647"},
+               {"0x.8p-2147483647", 64, 'p', 0, "0x.8p-2147483647"},
+               {"1p-2147483649", 64, 'p', 0, "0x.8p-2147483648"},
 
                // TODO(gri) need tests for actual large Floats
 
@@ -438,9 +467,6 @@ func TestFloatFormat(t *testing.T) {
                value  interface{} // float32, float64, or string (== 512bit *Float)
                want   string
        }{
-               // TODO(gri) uncomment the disabled 'g'/'G' formats
-               //           below once (*Float).Text supports prec < 0
-
                // from fmt/fmt_test.go
                {"%+.3e", 0.0, "+0.000e+00"},
                {"%+.3e", 1.0, "+1.000e+00"},
@@ -471,9 +497,9 @@ func TestFloatFormat(t *testing.T) {
                {"%f", 1234.5678e-8, "0.000012"},
                {"%f", -7.0, "-7.000000"},
                {"%f", -1e-9, "-0.000000"},
-               // {"%g", 1234.5678e3, "1.2345678e+06"},
-               // {"%g", float32(1234.5678e3), "1.2345678e+06"},
-               // {"%g", 1234.5678e-8, "1.2345678e-05"},
+               {"%g", 1234.5678e3, "1.2345678e+06"},
+               {"%g", float32(1234.5678e3), "1.2345678e+06"},
+               {"%g", 1234.5678e-8, "1.2345678e-05"},
                {"%g", -7.0, "-7"},
                {"%g", -1e-9, "-1e-09"},
                {"%g", float32(-1e-9), "-1e-09"},
@@ -482,9 +508,9 @@ func TestFloatFormat(t *testing.T) {
                {"%E", 1234.5678e-8, "1.234568E-05"},
                {"%E", -7.0, "-7.000000E+00"},
                {"%E", -1e-9, "-1.000000E-09"},
-               // {"%G", 1234.5678e3, "1.2345678E+06"},
-               // {"%G", float32(1234.5678e3), "1.2345678E+06"},
-               // {"%G", 1234.5678e-8, "1.2345678E-05"},
+               {"%G", 1234.5678e3, "1.2345678E+06"},
+               {"%G", float32(1234.5678e3), "1.2345678E+06"},
+               {"%G", 1234.5678e-8, "1.2345678E-05"},
                {"%G", -7.0, "-7"},
                {"%G", -1e-9, "-1E-09"},
                {"%G", float32(-1e-9), "-1E-09"},
@@ -500,9 +526,9 @@ func TestFloatFormat(t *testing.T) {
                {"%-20f", 1.23456789e3, "1234.567890         "},
                {"%20.8f", 1.23456789e3, "       1234.56789000"},
                {"%20.8f", 1.23456789e-3, "          0.00123457"},
-               // {"%g", 1.23456789e3, "1234.56789"},
-               // {"%g", 1.23456789e-3, "0.00123456789"},
-               // {"%g", 1.23456789e20, "1.23456789e+20"},
+               {"%g", 1.23456789e3, "1234.56789"},
+               {"%g", 1.23456789e-3, "0.00123456789"},
+               {"%g", 1.23456789e20, "1.23456789e+20"},
                {"%20e", math.Inf(1), "                +Inf"},
                {"%-20f", math.Inf(-1), "-Inf                "},
 
@@ -541,7 +567,6 @@ func TestFloatFormat(t *testing.T) {
                {"%v", -1e-9, "-1e-09"},
                {"%v", float32(-1e-9), "-1e-09"},
                {"%010v", 0.0, "0000000000"},
-               {"%010v", 0.0, "0000000000"},
 
                // *Float cases
                {"%.20f", "1e-20", "0.00000000000000000001"},
@@ -571,3 +596,67 @@ func TestFloatFormat(t *testing.T) {
                }
        }
 }
+
+func BenchmarkParseFloatSmallExp(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               for _, s := range []string{
+                       "1e0",
+                       "1e-1",
+                       "1e-2",
+                       "1e-3",
+                       "1e-4",
+                       "1e-5",
+                       "1e-10",
+                       "1e-20",
+                       "1e-50",
+                       "1e1",
+                       "1e2",
+                       "1e3",
+                       "1e4",
+                       "1e5",
+                       "1e10",
+                       "1e20",
+                       "1e50",
+               } {
+                       var x Float
+                       _, _, err := x.Parse(s, 0)
+                       if err != nil {
+                               b.Fatalf("%s: %v", s, err)
+                       }
+               }
+       }
+}
+
+func BenchmarkParseFloatLargeExp(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               for _, s := range []string{
+                       "1e0",
+                       "1e-10",
+                       "1e-20",
+                       "1e-30",
+                       "1e-40",
+                       "1e-50",
+                       "1e-100",
+                       "1e-500",
+                       "1e-1000",
+                       "1e-5000",
+                       "1e-10000",
+                       "1e10",
+                       "1e20",
+                       "1e30",
+                       "1e40",
+                       "1e50",
+                       "1e100",
+                       "1e500",
+                       "1e1000",
+                       "1e5000",
+                       "1e10000",
+               } {
+                       var x Float
+                       _, _, err := x.Parse(s, 0)
+                       if err != nil {
+                               b.Fatalf("%s: %v", s, err)
+                       }
+               }
+       }
+}
index 69686b7d16b9fa05291f5df47213f3a369257a17..05bce613a807be07f09ade901be4291284aeb35c 100644 (file)
@@ -111,3 +111,33 @@ func ExampleFloat_Cmp() {
        // +Inf   1.2    1
        // +Inf  +Inf    0
 }
+
+func ExampleRoundingMode() {
+       operands := []float64{2.6, 2.5, 2.1, -2.1, -2.5, -2.6}
+
+       fmt.Print("   x")
+       for mode := big.ToNearestEven; mode <= big.ToPositiveInf; mode++ {
+               fmt.Printf("  %s", mode)
+       }
+       fmt.Println()
+
+       for _, f64 := range operands {
+               fmt.Printf("%4g", f64)
+               for mode := big.ToNearestEven; mode <= big.ToPositiveInf; mode++ {
+                       // sample operands above require 2 bits to represent mantissa
+                       // set binary precision to 2 to round them to integer values
+                       f := new(big.Float).SetPrec(2).SetMode(mode).SetFloat64(f64)
+                       fmt.Printf("  %*g", len(mode.String()), f)
+               }
+               fmt.Println()
+       }
+
+       // Output:
+       //    x  ToNearestEven  ToNearestAway  ToZero  AwayFromZero  ToNegativeInf  ToPositiveInf
+       //  2.6              3              3       2             3              2              3
+       //  2.5              2              3       2             3              2              3
+       //  2.1              2              2       2             3              2              3
+       // -2.1             -2             -2      -2            -3             -3             -2
+       // -2.5             -2             -3      -2            -3             -3             -2
+       // -2.6             -3             -3      -2            -3             -3             -2
+}
diff --git a/libgo/go/math/big/floatmarsh.go b/libgo/go/math/big/floatmarsh.go
new file mode 100644 (file)
index 0000000..44987ee
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2015 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.
+
+// This file implements encoding/decoding of Floats.
+
+package big
+
+import "fmt"
+
+// MarshalText implements the encoding.TextMarshaler interface.
+// Only the Float value is marshaled (in full precision), other
+// attributes such as precision or accuracy are ignored.
+func (x *Float) MarshalText() (text []byte, err error) {
+       if x == nil {
+               return []byte("<nil>"), nil
+       }
+       var buf []byte
+       return x.Append(buf, 'g', -1), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+// The result is rounded per the precision and rounding mode of z.
+// If z's precision is 0, it is changed to 64 before rounding takes
+// effect.
+func (z *Float) UnmarshalText(text []byte) error {
+       // TODO(gri): get rid of the []byte/string conversion
+       _, _, err := z.Parse(string(text), 0)
+       if err != nil {
+               err = fmt.Errorf("math/big: cannot unmarshal %q into a *big.Float (%v)", text, err)
+       }
+       return err
+}
diff --git a/libgo/go/math/big/floatmarsh_test.go b/libgo/go/math/big/floatmarsh_test.go
new file mode 100644 (file)
index 0000000..d7ef2fc
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright 2015 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 big
+
+import (
+       "encoding/json"
+       "testing"
+)
+
+var floatVals = []string{
+       "0",
+       "1",
+       "0.1",
+       "2.71828",
+       "1234567890",
+       "3.14e1234",
+       "3.14e-1234",
+       "0.738957395793475734757349579759957975985497e100",
+       "0.73895739579347546656564656573475734957975995797598589749859834759476745986795497e100",
+       "inf",
+       "Inf",
+}
+
+func TestFloatJSONEncoding(t *testing.T) {
+       for _, test := range floatVals {
+               for _, sign := range []string{"", "+", "-"} {
+                       for _, prec := range []uint{0, 1, 2, 10, 53, 64, 100, 1000} {
+                               x := sign + test
+                               var tx Float
+                               _, _, err := tx.SetPrec(prec).Parse(x, 0)
+                               if err != nil {
+                                       t.Errorf("parsing of %s (prec = %d) failed (invalid test case): %v", x, prec, err)
+                                       continue
+                               }
+                               b, err := json.Marshal(&tx)
+                               if err != nil {
+                                       t.Errorf("marshaling of %v (prec = %d) failed: %v", &tx, prec, err)
+                                       continue
+                               }
+                               var rx Float
+                               rx.SetPrec(prec)
+                               if err := json.Unmarshal(b, &rx); err != nil {
+                                       t.Errorf("unmarshaling of %v (prec = %d) failed: %v", &tx, prec, err)
+                                       continue
+                               }
+                               if rx.Cmp(&tx) != 0 {
+                                       t.Errorf("JSON encoding of %v (prec = %d) failed: got %v want %v", &tx, prec, &rx, &tx)
+                               }
+                       }
+               }
+       }
+}
index 5c5f2cea460cc87a211e527d24f218f820c12a11..c5cdb5eb705087ece832dfe024c0b71a317b1888 100644 (file)
@@ -9,9 +9,9 @@
 package big
 
 import (
+       "bytes"
        "fmt"
        "strconv"
-       "strings"
 )
 
 // Text converts the floating-point number x to a string according
@@ -37,16 +37,16 @@ import (
 // printed by the 'e', 'E', 'f', 'g', and 'G' formats. For 'e', 'E', and 'f'
 // it is the number of digits after the decimal point. For 'g' and 'G' it is
 // the total number of digits. A negative precision selects the smallest
-// number of digits necessary to identify the value x uniquely.
+// number of decimal digits necessary to identify the value x uniquely using
+// x.Prec() mantissa bits.
 // The prec value is ignored for the 'b' or 'p' format.
-//
-// BUG(gri) Float.Text does not accept negative precisions (issue #10991).
 func (x *Float) Text(format byte, prec int) string {
        const extra = 10 // TODO(gri) determine a good/better value here
        return string(x.Append(make([]byte, 0, prec+extra), format, prec))
 }
 
 // String formats x like x.Text('g', 10).
+// (String must be called explicitly, Float.Format does not support %s verb.)
 func (x *Float) String() string {
        return x.Text('g', 10)
 }
@@ -83,6 +83,7 @@ func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
        // 1) convert Float to multiprecision decimal
        var d decimal // == 0.0
        if x.form == finite {
+               // x != 0
                d.init(x.mant, int(x.exp)-x.mant.bitLen())
        }
 
@@ -90,9 +91,7 @@ func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
        shortest := false
        if prec < 0 {
                shortest = true
-               panic("unimplemented")
-               // TODO(gri) complete this
-               // roundShortest(&d, f.mant, int(f.exp))
+               roundShortest(&d, x)
                // Precision for shortest representation mode.
                switch fmt {
                case 'e', 'E':
@@ -158,6 +157,80 @@ func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
        return append(buf, '%', fmt)
 }
 
+func roundShortest(d *decimal, x *Float) {
+       // if the mantissa is zero, the number is zero - stop now
+       if len(d.mant) == 0 {
+               return
+       }
+
+       // Approach: All numbers in the interval [x - 1/2ulp, x + 1/2ulp]
+       // (possibly exclusive) round to x for the given precision of x.
+       // Compute the lower and upper bound in decimal form and find the
+       // shortest decimal number d such that lower <= d <= upper.
+
+       // TODO(gri) strconv/ftoa.do describes a shortcut in some cases.
+       // See if we can use it (in adjusted form) here as well.
+
+       // 1) Compute normalized mantissa mant and exponent exp for x such
+       // that the lsb of mant corresponds to 1/2 ulp for the precision of
+       // x (i.e., for mant we want x.prec + 1 bits).
+       mant := nat(nil).set(x.mant)
+       exp := int(x.exp) - mant.bitLen()
+       s := mant.bitLen() - int(x.prec+1)
+       switch {
+       case s < 0:
+               mant = mant.shl(mant, uint(-s))
+       case s > 0:
+               mant = mant.shr(mant, uint(+s))
+       }
+       exp += s
+       // x = mant * 2**exp with lsb(mant) == 1/2 ulp of x.prec
+
+       // 2) Compute lower bound by subtracting 1/2 ulp.
+       var lower decimal
+       var tmp nat
+       lower.init(tmp.sub(mant, natOne), exp)
+
+       // 3) Compute upper bound by adding 1/2 ulp.
+       var upper decimal
+       upper.init(tmp.add(mant, natOne), exp)
+
+       // The upper and lower bounds are possible outputs only if
+       // the original mantissa is even, so that ToNearestEven rounding
+       // would round to the original mantissa and not the neighbors.
+       inclusive := mant[0]&2 == 0 // test bit 1 since original mantissa was shifted by 1
+
+       // Now we can figure out the minimum number of digits required.
+       // Walk along until d has distinguished itself from upper and lower.
+       for i, m := range d.mant {
+               l := lower.at(i)
+               u := upper.at(i)
+
+               // Okay to round down (truncate) if lower has a different digit
+               // or if lower is inclusive and is exactly the result of rounding
+               // down (i.e., and we have reached the final digit of lower).
+               okdown := l != m || inclusive && i+1 == len(lower.mant)
+
+               // Okay to round up if upper has a different digit and either upper
+               // is inclusive or upper is bigger than the result of rounding up.
+               okup := m != u && (inclusive || m+1 < u || i+1 < len(upper.mant))
+
+               // If it's okay to do either, then round to the nearest one.
+               // If it's okay to do only one, do it.
+               switch {
+               case okdown && okup:
+                       d.round(i + 1)
+                       return
+               case okdown:
+                       d.roundDown(i + 1)
+                       return
+               case okup:
+                       d.roundUp(i + 1)
+                       return
+               }
+       }
+}
+
 // %e: d.ddddde±dd
 func fmtE(buf []byte, fmt byte, prec int, d decimal) []byte {
        // first digit
@@ -219,11 +292,7 @@ func fmtF(buf []byte, prec int, d decimal) []byte {
        if prec > 0 {
                buf = append(buf, '.')
                for i := 0; i < prec; i++ {
-                       ch := byte('0')
-                       if j := d.exp + i; 0 <= j && j < len(d.mant) {
-                               ch = d.mant[j]
-                       }
-                       buf = append(buf, ch)
+                       buf = append(buf, d.at(d.exp+i))
                }
        }
 
@@ -255,7 +324,7 @@ func (x *Float) fmtB(buf []byte) []byte {
                m = nat(nil).shr(m, uint(w-x.prec))
        }
 
-       buf = append(buf, m.decimalString()...)
+       buf = append(buf, m.utoa(10)...)
        buf = append(buf, 'p')
        e := int64(x.exp) - int64(x.prec)
        if e >= 0 {
@@ -289,7 +358,7 @@ func (x *Float) fmtP(buf []byte) []byte {
        m = m[i:]
 
        buf = append(buf, "0x."...)
-       buf = append(buf, strings.TrimRight(m.hexString(), "0")...)
+       buf = append(buf, bytes.TrimRight(m.utoa(16), "0")...)
        buf = append(buf, 'p')
        if x.exp >= 0 {
                buf = append(buf, '+')
@@ -314,10 +383,6 @@ func min(x, y int) int {
 // '+' and ' ' for sign control, '0' for space or zero padding,
 // and '-' for left or right justification. See the fmt package
 // for details.
-//
-// BUG(gri) A missing precision for the 'g' format, or a negative
-//          (via '*') precision is not yet supported. Instead the
-//          default precision (6) is used in that case (issue #10991).
 func (x *Float) Format(s fmt.State, format rune) {
        prec, hasPrec := s.Precision()
        if !hasPrec {
@@ -336,8 +401,7 @@ func (x *Float) Format(s fmt.State, format rune) {
                fallthrough
        case 'g', 'G':
                if !hasPrec {
-                       // TODO(gri) uncomment once (*Float).Text handles prec < 0
-                       // prec = -1 // default precision for 'g', 'G'
+                       prec = -1 // default precision for 'g', 'G'
                }
        default:
                fmt.Fprintf(s, "%%!%c(*big.Float=%s)", format, x.String())
index 65334e0ef5501a9caeceffb2067644293abca1d8..67ab7042ffe699b41d8da7b0081f670d163a6cf9 100644 (file)
@@ -273,7 +273,7 @@ func (z *Int) Mod(x, y *Int) *Int {
 // DivMod implements Euclidean division and modulus (unlike Go):
 //
 //     q = x div y  such that
-//     m = x - y*q  with 0 <= m < |q|
+//     m = x - y*q  with 0 <= m < |y|
 //
 // (See Raymond T. Boute, ``The Euclidean definition of the functions
 // div and mod''. ACM Transactions on Programming Languages and
@@ -551,8 +551,11 @@ func (z *Int) binaryGCD(a, b *Int) *Int {
 }
 
 // ProbablyPrime performs n Miller-Rabin tests to check whether x is prime.
-// If it returns true, x is prime with probability 1 - 1/4^n.
-// If it returns false, x is not prime. n must be > 0.
+// If x is prime, it returns true.
+// If x is not prime, it returns false with probability at least 1 - ¼ⁿ.
+//
+// It is not suitable for judging primes that an adversary may have crafted
+// to fool this test.
 func (x *Int) ProbablyPrime(n int) bool {
        if n <= 0 {
                panic("non-positive n for ProbablyPrime")
@@ -640,23 +643,23 @@ func Jacobi(x, y *Int) int {
        }
 }
 
-// ModSqrt sets z to a square root of x mod p if such a square root exists, and
-// returns z. The modulus p must be an odd prime. If x is not a square mod p,
-// ModSqrt leaves z unchanged and returns nil. This function panics if p is
-// not an odd integer.
-func (z *Int) ModSqrt(x, p *Int) *Int {
-       switch Jacobi(x, p) {
-       case -1:
-               return nil // x is not a square mod p
-       case 0:
-               return z.SetInt64(0) // sqrt(0) mod p = 0
-       case 1:
-               break
-       }
-       if x.neg || x.Cmp(p) >= 0 { // ensure 0 <= x < p
-               x = new(Int).Mod(x, p)
-       }
+// modSqrt3Mod4 uses the identity
+//      (a^((p+1)/4))^2  mod p
+//   == u^(p+1)          mod p
+//   == u^2              mod p
+// to calculate the square root of any quadratic residue mod p quickly for 3
+// mod 4 primes.
+func (z *Int) modSqrt3Mod4Prime(x, p *Int) *Int {
+       z.Set(p)         // z = p
+       z.Add(z, intOne) // z = p + 1
+       z.Rsh(z, 2)      // z = (p + 1) / 4
+       z.Exp(x, z, p)   // z = x^z mod p
+       return z
+}
 
+// modSqrtTonelliShanks uses the Tonelli-Shanks algorithm to find the square
+// root of a quadratic residue modulo any prime.
+func (z *Int) modSqrtTonelliShanks(x, p *Int) *Int {
        // Break p-1 into s*2^e such that s is odd.
        var s Int
        s.Sub(p, intOne)
@@ -703,6 +706,31 @@ func (z *Int) ModSqrt(x, p *Int) *Int {
        }
 }
 
+// ModSqrt sets z to a square root of x mod p if such a square root exists, and
+// returns z. The modulus p must be an odd prime. If x is not a square mod p,
+// ModSqrt leaves z unchanged and returns nil. This function panics if p is
+// not an odd integer.
+func (z *Int) ModSqrt(x, p *Int) *Int {
+       switch Jacobi(x, p) {
+       case -1:
+               return nil // x is not a square mod p
+       case 0:
+               return z.SetInt64(0) // sqrt(0) mod p = 0
+       case 1:
+               break
+       }
+       if x.neg || x.Cmp(p) >= 0 { // ensure 0 <= x < p
+               x = new(Int).Mod(x, p)
+       }
+
+       // Check whether p is 3 mod 4, and if so, use the faster algorithm.
+       if len(p.abs) > 0 && p.abs[0]%4 == 3 {
+               return z.modSqrt3Mod4Prime(x, p)
+       }
+       // Otherwise, use Tonelli-Shanks.
+       return z.modSqrtTonelliShanks(x, p)
+}
+
 // Lsh sets z = x << n and returns z.
 func (z *Int) Lsh(x *Int, n uint) *Int {
        z.abs = z.abs.shl(x.abs, n)
@@ -904,65 +932,3 @@ func (z *Int) Not(x *Int) *Int {
        z.neg = true // z cannot be zero if x is positive
        return z
 }
-
-// Gob codec version. Permits backward-compatible changes to the encoding.
-const intGobVersion byte = 1
-
-// GobEncode implements the gob.GobEncoder interface.
-func (x *Int) GobEncode() ([]byte, error) {
-       if x == nil {
-               return nil, nil
-       }
-       buf := make([]byte, 1+len(x.abs)*_S) // extra byte for version and sign bit
-       i := x.abs.bytes(buf) - 1            // i >= 0
-       b := intGobVersion << 1              // make space for sign bit
-       if x.neg {
-               b |= 1
-       }
-       buf[i] = b
-       return buf[i:], nil
-}
-
-// GobDecode implements the gob.GobDecoder interface.
-func (z *Int) GobDecode(buf []byte) error {
-       if len(buf) == 0 {
-               // Other side sent a nil or default value.
-               *z = Int{}
-               return nil
-       }
-       b := buf[0]
-       if b>>1 != intGobVersion {
-               return fmt.Errorf("Int.GobDecode: encoding version %d not supported", b>>1)
-       }
-       z.neg = b&1 != 0
-       z.abs = z.abs.setBytes(buf[1:])
-       return nil
-}
-
-// MarshalJSON implements the json.Marshaler interface.
-func (z *Int) MarshalJSON() ([]byte, error) {
-       // TODO(gri): get rid of the []byte/string conversions
-       return []byte(z.String()), nil
-}
-
-// UnmarshalJSON implements the json.Unmarshaler interface.
-func (z *Int) UnmarshalJSON(text []byte) error {
-       // TODO(gri): get rid of the []byte/string conversions
-       if _, ok := z.SetString(string(text), 0); !ok {
-               return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
-       }
-       return nil
-}
-
-// MarshalText implements the encoding.TextMarshaler interface.
-func (z *Int) MarshalText() (text []byte, err error) {
-       return []byte(z.String()), nil
-}
-
-// UnmarshalText implements the encoding.TextUnmarshaler interface.
-func (z *Int) UnmarshalText(text []byte) error {
-       if _, ok := z.SetString(string(text), 0); !ok {
-               return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
-       }
-       return nil
-}
index 88c8c2bb64167e749ef98422dd38f760010a30ba..45a3765d3eee36d9669d7c5fda9211836b123ee0 100644 (file)
@@ -6,10 +6,7 @@ package big
 
 import (
        "bytes"
-       "encoding/gob"
        "encoding/hex"
-       "encoding/json"
-       "encoding/xml"
        "fmt"
        "math/rand"
        "testing"
@@ -387,6 +384,11 @@ func TestSetBytes(t *testing.T) {
 }
 
 func checkBytes(b []byte) bool {
+       // trim leading zero bytes since Bytes() won't return them
+       // (was issue 12231)
+       for len(b) > 0 && b[0] == 0 {
+               b = b[1:]
+       }
        b2 := new(Int).SetBytes(b).Bytes()
        return bytes.Equal(b, b2)
 }
@@ -542,6 +544,9 @@ var expTests = []struct {
        {"0x8000000000000000", "1000", "6719", "1603"},
        {"0x8000000000000000", "1000000", "6719", "3199"},
        {"0x8000000000000000", "-1000000", "6719", "1"},
+
+       {"0xffffffffffffffffffffffffffffffff", "0x12345678123456781234567812345678123456789", "0x01112222333344445555666677778889", "0x36168FA1DB3AAE6C8CE647E137F97A"},
+
        {
                "2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347",
                "298472983472983471903246121093472394872319615612417471234712061",
@@ -549,12 +554,24 @@ var expTests = []struct {
                "23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291",
        },
        // test case for issue 8822
+       {
+               "11001289118363089646017359372117963499250546375269047542777928006103246876688756735760905680604646624353196869572752623285140408755420374049317646428185270079555372763503115646054602867593662923894140940837479507194934267532831694565516466765025434902348314525627418515646588160955862839022051353653052947073136084780742729727874803457643848197499548297570026926927502505634297079527299004267769780768565695459945235586892627059178884998772989397505061206395455591503771677500931269477503508150175717121828518985901959919560700853226255420793148986854391552859459511723547532575574664944815966793196961286234040892865",
+               "0xB08FFB20760FFED58FADA86DFEF71AD72AA0FA763219618FE022C197E54708BB1191C66470250FCE8879487507CEE41381CA4D932F81C2B3F1AB20B539D50DCD",
+               "0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73",
+               "21484252197776302499639938883777710321993113097987201050501182909581359357618579566746556372589385361683610524730509041328855066514963385522570894839035884713051640171474186548713546686476761306436434146475140156284389181808675016576845833340494848283681088886584219750554408060556769486628029028720727393293111678826356480455433909233520504112074401376133077150471237549474149190242010469539006449596611576612573955754349042329130631128234637924786466585703488460540228477440853493392086251021228087076124706778899179648655221663765993962724699135217212118535057766739392069738618682722216712319320435674779146070442",
+       },
        {
                "-0x1BCE04427D8032319A89E5C4136456671AC620883F2C4139E57F91307C485AD2D6204F4F87A58262652DB5DBBAC72B0613E51B835E7153BEC6068F5C8D696B74DBD18FEC316AEF73985CF0475663208EB46B4F17DD9DA55367B03323E5491A70997B90C059FB34809E6EE55BCFBD5F2F52233BFE62E6AA9E4E26A1D4C2439883D14F2633D55D8AA66A1ACD5595E778AC3A280517F1157989E70C1A437B849F1877B779CC3CDDEDE2DAA6594A6C66D181A00A5F777EE60596D8773998F6E988DEAE4CCA60E4DDCF9590543C89F74F603259FCAD71660D30294FBBE6490300F78A9D63FA660DC9417B8B9DDA28BEB3977B621B988E23D4D954F322C3540541BC649ABD504C50FADFD9F0987D58A2BF689313A285E773FF02899A6EF887D1D4A0D2",
                "0xB08FFB20760FFED58FADA86DFEF71AD72AA0FA763219618FE022C197E54708BB1191C66470250FCE8879487507CEE41381CA4D932F81C2B3F1AB20B539D50DCD",
                "0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73",
                "21484252197776302499639938883777710321993113097987201050501182909581359357618579566746556372589385361683610524730509041328855066514963385522570894839035884713051640171474186548713546686476761306436434146475140156284389181808675016576845833340494848283681088886584219750554408060556769486628029028720727393293111678826356480455433909233520504112074401376133077150471237549474149190242010469539006449596611576612573955754349042329130631128234637924786466585703488460540228477440853493392086251021228087076124706778899179648655221663765993962724699135217212118535057766739392069738618682722216712319320435674779146070442",
        },
+
+       // test cases for issue 13907
+       {"0xffffffff00000001", "0xffffffff00000001", "0xffffffff00000001", "0"},
+       {"0xffffffffffffffff00000001", "0xffffffffffffffff00000001", "0xffffffffffffffff00000001", "0"},
+       {"0xffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffff00000001", "0"},
+       {"0xffffffffffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffffffffffff00000001", "0"},
 }
 
 func TestExp(t *testing.T) {
@@ -582,7 +599,7 @@ func TestExp(t *testing.T) {
                        t.Errorf("#%d: %v is not normalized", i, *z1)
                }
                if z1.Cmp(out) != 0 {
-                       t.Errorf("#%d: got %s want %s", i, z1, out)
+                       t.Errorf("#%d: got %x want %x", i, z1, out)
                }
 
                if m == nil {
@@ -591,7 +608,7 @@ func TestExp(t *testing.T) {
                        m = &Int{abs: nat{}} // m != nil && len(m.abs) == 0
                        z2 := new(Int).Exp(x, y, m)
                        if z2.Cmp(z1) != 0 {
-                               t.Errorf("#%d: got %s want %s", i, z2, z1)
+                               t.Errorf("#%d: got %x want %x", i, z2, z1)
                        }
                }
        }
@@ -693,7 +710,9 @@ func TestGcd(t *testing.T) {
                testGcd(t, d, x, y, a, b)
        }
 
-       quick.Check(checkGcd, nil)
+       if err := quick.Check(checkGcd, nil); err != nil {
+               t.Error(err)
+       }
 }
 
 var primes = []string{
@@ -1180,6 +1199,53 @@ func BenchmarkBitsetNegOrig(b *testing.B) {
        }
 }
 
+// tri generates the trinomial 2**(n*2) - 2**n - 1, which is always 3 mod 4 and
+// 7 mod 8, so that 2 is always a quadratic residue.
+func tri(n uint) *Int {
+       x := NewInt(1)
+       x.Lsh(x, n)
+       x2 := new(Int).Lsh(x, n)
+       x2.Sub(x2, x)
+       x2.Sub(x2, intOne)
+       return x2
+}
+
+func BenchmarkModSqrt225_Tonelli(b *testing.B) {
+       p := tri(225)
+       x := NewInt(2)
+       for i := 0; i < b.N; i++ {
+               x.SetUint64(2)
+               x.modSqrtTonelliShanks(x, p)
+       }
+}
+
+func BenchmarkModSqrt224_3Mod4(b *testing.B) {
+       p := tri(225)
+       x := new(Int).SetUint64(2)
+       for i := 0; i < b.N; i++ {
+               x.SetUint64(2)
+               x.modSqrt3Mod4Prime(x, p)
+       }
+}
+
+func BenchmarkModSqrt5430_Tonelli(b *testing.B) {
+       p := tri(5430)
+       x := new(Int).SetUint64(2)
+       for i := 0; i < b.N; i++ {
+               x.SetUint64(2)
+               x.modSqrtTonelliShanks(x, p)
+       }
+}
+
+func BenchmarkModSqrt5430_3Mod4(b *testing.B) {
+       p := tri(5430)
+       x := new(Int).SetUint64(2)
+       for i := 0; i < b.N; i++ {
+               x.SetUint64(2)
+               x.modSqrt3Mod4Prime(x, p)
+       }
+}
+
 func TestBitwise(t *testing.T) {
        x := new(Int)
        y := new(Int)
@@ -1318,6 +1384,14 @@ func TestModSqrt(t *testing.T) {
                                t.Errorf("#%d: failed (sqrt(e) = %s)", i, &sqrt)
                        }
                }
+
+               if testing.Short() && i > 2 {
+                       break
+               }
+       }
+
+       if testing.Short() {
+               return
        }
 
        // exhaustive test for small values
@@ -1401,138 +1475,6 @@ func TestJacobiPanic(t *testing.T) {
        panic(failureMsg)
 }
 
-var encodingTests = []string{
-       "-539345864568634858364538753846587364875430589374589",
-       "-678645873",
-       "-100",
-       "-2",
-       "-1",
-       "0",
-       "1",
-       "2",
-       "10",
-       "42",
-       "1234567890",
-       "298472983472983471903246121093472394872319615612417471234712061",
-}
-
-func TestIntGobEncoding(t *testing.T) {
-       var medium bytes.Buffer
-       enc := gob.NewEncoder(&medium)
-       dec := gob.NewDecoder(&medium)
-       for _, test := range encodingTests {
-               medium.Reset() // empty buffer for each test case (in case of failures)
-               var tx Int
-               tx.SetString(test, 10)
-               if err := enc.Encode(&tx); err != nil {
-                       t.Errorf("encoding of %s failed: %s", &tx, err)
-               }
-               var rx Int
-               if err := dec.Decode(&rx); err != nil {
-                       t.Errorf("decoding of %s failed: %s", &tx, err)
-               }
-               if rx.Cmp(&tx) != 0 {
-                       t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx)
-               }
-       }
-}
-
-// Sending a nil Int pointer (inside a slice) on a round trip through gob should yield a zero.
-// TODO: top-level nils.
-func TestGobEncodingNilIntInSlice(t *testing.T) {
-       buf := new(bytes.Buffer)
-       enc := gob.NewEncoder(buf)
-       dec := gob.NewDecoder(buf)
-
-       var in = make([]*Int, 1)
-       err := enc.Encode(&in)
-       if err != nil {
-               t.Errorf("gob encode failed: %q", err)
-       }
-       var out []*Int
-       err = dec.Decode(&out)
-       if err != nil {
-               t.Fatalf("gob decode failed: %q", err)
-       }
-       if len(out) != 1 {
-               t.Fatalf("wrong len; want 1 got %d", len(out))
-       }
-       var zero Int
-       if out[0].Cmp(&zero) != 0 {
-               t.Errorf("transmission of (*Int)(nill) failed: got %s want 0", out)
-       }
-}
-
-func TestIntJSONEncoding(t *testing.T) {
-       for _, test := range encodingTests {
-               var tx Int
-               tx.SetString(test, 10)
-               b, err := json.Marshal(&tx)
-               if err != nil {
-                       t.Errorf("marshaling of %s failed: %s", &tx, err)
-               }
-               var rx Int
-               if err := json.Unmarshal(b, &rx); err != nil {
-                       t.Errorf("unmarshaling of %s failed: %s", &tx, err)
-               }
-               if rx.Cmp(&tx) != 0 {
-                       t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
-               }
-       }
-}
-
-var intVals = []string{
-       "-141592653589793238462643383279502884197169399375105820974944592307816406286",
-       "-1415926535897932384626433832795028841971",
-       "-141592653589793",
-       "-1",
-       "0",
-       "1",
-       "141592653589793",
-       "1415926535897932384626433832795028841971",
-       "141592653589793238462643383279502884197169399375105820974944592307816406286",
-}
-
-func TestIntJSONEncodingTextMarshaller(t *testing.T) {
-       for _, num := range intVals {
-               var tx Int
-               tx.SetString(num, 0)
-               b, err := json.Marshal(&tx)
-               if err != nil {
-                       t.Errorf("marshaling of %s failed: %s", &tx, err)
-                       continue
-               }
-               var rx Int
-               if err := json.Unmarshal(b, &rx); err != nil {
-                       t.Errorf("unmarshaling of %s failed: %s", &tx, err)
-                       continue
-               }
-               if rx.Cmp(&tx) != 0 {
-                       t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
-               }
-       }
-}
-
-func TestIntXMLEncodingTextMarshaller(t *testing.T) {
-       for _, num := range intVals {
-               var tx Int
-               tx.SetString(num, 0)
-               b, err := xml.Marshal(&tx)
-               if err != nil {
-                       t.Errorf("marshaling of %s failed: %s", &tx, err)
-                       continue
-               }
-               var rx Int
-               if err := xml.Unmarshal(b, &rx); err != nil {
-                       t.Errorf("unmarshaling of %s failed: %s", &tx, err)
-                       continue
-               }
-               if rx.Cmp(&tx) != 0 {
-                       t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
-               }
-       }
-}
-
 func TestIssue2607(t *testing.T) {
        // This code sequence used to hang.
        n := NewInt(10)
index 9c68a22bed8055f7a83597507e6eee9e897bbb80..56a75f87ae2fcdee52c0846b469745473e038760 100644 (file)
@@ -12,30 +12,34 @@ import (
        "io"
 )
 
-func (x *Int) String() string {
-       switch {
-       case x == nil:
+// TODO(gri) Should rename itoa to utoa (there's no sign). That
+// would permit the introduction of itoa which is like utoa but
+// reserves a byte for a possible sign that's passed in. That
+// would permit Int.Text to be implemented w/o the need for
+// string copy if the number is negative.
+
+// Text returns the string representation of x in the given base.
+// Base must be between 2 and 36, inclusive. The result uses the
+// lower-case letters 'a' to 'z' for digit values >= 10. No base
+// prefix (such as "0x") is added to the string.
+func (x *Int) Text(base int) string {
+       if x == nil {
                return "<nil>"
-       case x.neg:
-               return "-" + x.abs.decimalString()
        }
-       return x.abs.decimalString()
+       return string(x.abs.itoa(x.neg, base))
 }
 
-func charset(ch rune) string {
-       switch ch {
-       case 'b':
-               return lowercaseDigits[0:2]
-       case 'o':
-               return lowercaseDigits[0:8]
-       case 'd', 's', 'v':
-               return lowercaseDigits[0:10]
-       case 'x':
-               return lowercaseDigits[0:16]
-       case 'X':
-               return uppercaseDigits[0:16]
+// Append appends the string representation of x, as generated by
+// x.Text(base), to buf and returns the extended buffer.
+func (x *Int) Append(buf []byte, base int) []byte {
+       if x == nil {
+               return append(buf, "<nil>"...)
        }
-       return "" // unknown format
+       return append(buf, x.abs.itoa(x.neg, base)...)
+}
+
+func (x *Int) String() string {
+       return x.Text(10)
 }
 
 // write count copies of text to s
@@ -60,15 +64,24 @@ func writeMultiple(s fmt.State, text string, count int) {
 // right justification.
 //
 func (x *Int) Format(s fmt.State, ch rune) {
-       cs := charset(ch)
-
-       // special cases
-       switch {
-       case cs == "":
+       // determine base
+       var base int
+       switch ch {
+       case 'b':
+               base = 2
+       case 'o':
+               base = 8
+       case 'd', 's', 'v':
+               base = 10
+       case 'x', 'X':
+               base = 16
+       default:
                // unknown format
                fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
                return
-       case x == nil:
+       }
+
+       if x == nil {
                fmt.Fprint(s, "<nil>")
                return
        }
@@ -97,35 +110,42 @@ func (x *Int) Format(s fmt.State, ch rune) {
                }
        }
 
-       // determine digits with base set by len(cs) and digit characters from cs
-       digits := x.abs.string(cs)
+       digits := x.abs.utoa(base)
+       if ch == 'X' {
+               // faster than bytes.ToUpper
+               for i, d := range digits {
+                       if 'a' <= d && d <= 'z' {
+                               digits[i] = 'A' + (d - 'a')
+                       }
+               }
+       }
 
        // number of characters for the three classes of number padding
-       var left int   // space characters to left of digits for right justification ("%8d")
-       var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d")
-       var right int  // space characters to right of digits for left justification ("%-8d")
+       var left int  // space characters to left of digits for right justification ("%8d")
+       var zeros int // zero characters (actually cs[0]) as left-most digits ("%.8d")
+       var right int // space characters to right of digits for left justification ("%-8d")
 
        // determine number padding from precision: the least number of digits to output
        precision, precisionSet := s.Precision()
        if precisionSet {
                switch {
                case len(digits) < precision:
-                       zeroes = precision - len(digits) // count of zero padding
-               case digits == "0" && precision == 0:
+                       zeros = precision - len(digits) // count of zero padding
+               case len(digits) == 1 && digits[0] == '0' && precision == 0:
                        return // print nothing if zero value (x == 0) and zero precision ("." or ".0")
                }
        }
 
        // determine field pad from width: the least number of characters to output
-       length := len(sign) + len(prefix) + zeroes + len(digits)
+       length := len(sign) + len(prefix) + zeros + len(digits)
        if width, widthSet := s.Width(); widthSet && length < width { // pad as specified
                switch d := width - length; {
                case s.Flag('-'):
                        // pad on the right with spaces; supersedes '0' when both specified
                        right = d
                case s.Flag('0') && !precisionSet:
-                       // pad with zeroes unless precision also specified
-                       zeroes = d
+                       // pad with zeros unless precision also specified
+                       zeros = d
                default:
                        // pad on the left with spaces
                        left = d
@@ -136,8 +156,8 @@ func (x *Int) Format(s fmt.State, ch rune) {
        writeMultiple(s, " ", left)
        writeMultiple(s, sign, 1)
        writeMultiple(s, prefix, 1)
-       writeMultiple(s, "0", zeroes)
-       writeMultiple(s, digits, 1)
+       writeMultiple(s, "0", zeros)
+       s.Write(digits)
        writeMultiple(s, " ", right)
 }
 
index 2deb84b48f68a4fd667faca454bcbac2dcc95504..514208145fdf119ba98191c9102ca7f9fec656d5 100644 (file)
@@ -17,19 +17,19 @@ var stringTests = []struct {
        val  int64
        ok   bool
 }{
-       {in: "", ok: false},
-       {in: "a", ok: false},
-       {in: "z", ok: false},
-       {in: "+", ok: false},
-       {in: "-", ok: false},
-       {in: "0b", ok: false},
-       {in: "0x", ok: false},
-       {in: "2", base: 2, ok: false},
-       {in: "0b2", base: 0, ok: false},
-       {in: "08", ok: false},
-       {in: "8", base: 8, ok: false},
-       {in: "0xg", base: 0, ok: false},
-       {in: "g", base: 16, ok: false},
+       {in: ""},
+       {in: "a"},
+       {in: "z"},
+       {in: "+"},
+       {in: "-"},
+       {in: "0b"},
+       {in: "0x"},
+       {in: "2", base: 2},
+       {in: "0b2", base: 0},
+       {in: "08"},
+       {in: "8", base: 8},
+       {in: "0xg", base: 0},
+       {in: "g", base: 16},
        {"0", "0", 0, 0, true},
        {"0", "0", 10, 0, true},
        {"0", "0", 16, 0, true},
@@ -41,7 +41,7 @@ var stringTests = []struct {
        {"-10", "-10", 16, -16, true},
        {"+10", "10", 16, 16, true},
        {"0x10", "16", 0, 16, true},
-       {in: "0x10", base: 16, ok: false},
+       {in: "0x10", base: 16},
        {"-0x10", "-16", 0, -16, true},
        {"+0x10", "16", 0, 16, true},
        {"00", "0", 0, 0, true},
@@ -58,6 +58,57 @@ var stringTests = []struct {
        {"1001010111", "1001010111", 2, 0x257, true},
 }
 
+func TestIntText(t *testing.T) {
+       z := new(Int)
+       for _, test := range stringTests {
+               if !test.ok {
+                       continue
+               }
+
+               _, ok := z.SetString(test.in, test.base)
+               if !ok {
+                       t.Errorf("%v: failed to parse", test)
+                       continue
+               }
+
+               base := test.base
+               if base == 0 {
+                       base = 10
+               }
+
+               if got := z.Text(base); got != test.out {
+                       t.Errorf("%v: got %s; want %s", test, got, test.out)
+               }
+       }
+}
+
+func TestAppendText(t *testing.T) {
+       z := new(Int)
+       var buf []byte
+       for _, test := range stringTests {
+               if !test.ok {
+                       continue
+               }
+
+               _, ok := z.SetString(test.in, test.base)
+               if !ok {
+                       t.Errorf("%v: failed to parse", test)
+                       continue
+               }
+
+               base := test.base
+               if base == 0 {
+                       base = 10
+               }
+
+               i := len(buf)
+               buf = z.Append(buf, base)
+               if got := string(buf[i:]); got != test.out {
+                       t.Errorf("%v: got %s; want %s", test, got, test.out)
+               }
+       }
+}
+
 func format(base int) string {
        switch base {
        case 2:
@@ -79,15 +130,13 @@ func TestGetString(t *testing.T) {
                z.SetInt64(test.val)
 
                if test.base == 10 {
-                       s := z.String()
-                       if s != test.out {
-                               t.Errorf("#%da got %s; want %s", i, s, test.out)
+                       if got := z.String(); got != test.out {
+                               t.Errorf("#%da got %s; want %s", i, got, test.out)
                        }
                }
 
-               s := fmt.Sprintf(format(test.base), z)
-               if s != test.out {
-                       t.Errorf("#%db got %s; want %s", i, s, test.out)
+               if got := fmt.Sprintf(format(test.base), z); got != test.out {
+                       t.Errorf("#%db got %s; want %s", i, got, test.out)
                }
        }
 }
diff --git a/libgo/go/math/big/intmarsh.go b/libgo/go/math/big/intmarsh.go
new file mode 100644 (file)
index 0000000..4ff57b6
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2015 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.
+
+// This file implements encoding/decoding of Ints.
+
+package big
+
+import "fmt"
+
+// Gob codec version. Permits backward-compatible changes to the encoding.
+const intGobVersion byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+func (x *Int) GobEncode() ([]byte, error) {
+       if x == nil {
+               return nil, nil
+       }
+       buf := make([]byte, 1+len(x.abs)*_S) // extra byte for version and sign bit
+       i := x.abs.bytes(buf) - 1            // i >= 0
+       b := intGobVersion << 1              // make space for sign bit
+       if x.neg {
+               b |= 1
+       }
+       buf[i] = b
+       return buf[i:], nil
+}
+
+// GobDecode implements the gob.GobDecoder interface.
+func (z *Int) GobDecode(buf []byte) error {
+       if len(buf) == 0 {
+               // Other side sent a nil or default value.
+               *z = Int{}
+               return nil
+       }
+       b := buf[0]
+       if b>>1 != intGobVersion {
+               return fmt.Errorf("Int.GobDecode: encoding version %d not supported", b>>1)
+       }
+       z.neg = b&1 != 0
+       z.abs = z.abs.setBytes(buf[1:])
+       return nil
+}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+func (x *Int) MarshalText() (text []byte, err error) {
+       if x == nil {
+               return []byte("<nil>"), nil
+       }
+       return x.abs.itoa(x.neg, 10), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+func (z *Int) UnmarshalText(text []byte) error {
+       // TODO(gri): get rid of the []byte/string conversion
+       if _, ok := z.SetString(string(text), 0); !ok {
+               return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
+       }
+       return nil
+}
+
+// The JSON marshallers are only here for API backward compatibility
+// (programs that explicitly look for these two methods). JSON works
+// fine with the TextMarshaler only.
+
+// MarshalJSON implements the json.Marshaler interface.
+func (x *Int) MarshalJSON() ([]byte, error) {
+       return x.MarshalText()
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+func (z *Int) UnmarshalJSON(text []byte) error {
+       return z.UnmarshalText(text)
+}
diff --git a/libgo/go/math/big/intmarsh_test.go b/libgo/go/math/big/intmarsh_test.go
new file mode 100644 (file)
index 0000000..f82956c
--- /dev/null
@@ -0,0 +1,121 @@
+// Copyright 2015 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 big
+
+import (
+       "bytes"
+       "encoding/gob"
+       "encoding/json"
+       "encoding/xml"
+       "testing"
+)
+
+var encodingTests = []string{
+       "0",
+       "1",
+       "2",
+       "10",
+       "1000",
+       "1234567890",
+       "298472983472983471903246121093472394872319615612417471234712061",
+}
+
+func TestIntGobEncoding(t *testing.T) {
+       var medium bytes.Buffer
+       enc := gob.NewEncoder(&medium)
+       dec := gob.NewDecoder(&medium)
+       for _, test := range encodingTests {
+               for _, sign := range []string{"", "+", "-"} {
+                       x := sign + test
+                       medium.Reset() // empty buffer for each test case (in case of failures)
+                       var tx Int
+                       tx.SetString(x, 10)
+                       if err := enc.Encode(&tx); err != nil {
+                               t.Errorf("encoding of %s failed: %s", &tx, err)
+                               continue
+                       }
+                       var rx Int
+                       if err := dec.Decode(&rx); err != nil {
+                               t.Errorf("decoding of %s failed: %s", &tx, err)
+                               continue
+                       }
+                       if rx.Cmp(&tx) != 0 {
+                               t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx)
+                       }
+               }
+       }
+}
+
+// Sending a nil Int pointer (inside a slice) on a round trip through gob should yield a zero.
+// TODO: top-level nils.
+func TestGobEncodingNilIntInSlice(t *testing.T) {
+       buf := new(bytes.Buffer)
+       enc := gob.NewEncoder(buf)
+       dec := gob.NewDecoder(buf)
+
+       var in = make([]*Int, 1)
+       err := enc.Encode(&in)
+       if err != nil {
+               t.Errorf("gob encode failed: %q", err)
+       }
+       var out []*Int
+       err = dec.Decode(&out)
+       if err != nil {
+               t.Fatalf("gob decode failed: %q", err)
+       }
+       if len(out) != 1 {
+               t.Fatalf("wrong len; want 1 got %d", len(out))
+       }
+       var zero Int
+       if out[0].Cmp(&zero) != 0 {
+               t.Fatalf("transmission of (*Int)(nil) failed: got %s want 0", out)
+       }
+}
+
+func TestIntJSONEncoding(t *testing.T) {
+       for _, test := range encodingTests {
+               for _, sign := range []string{"", "+", "-"} {
+                       x := sign + test
+                       var tx Int
+                       tx.SetString(x, 10)
+                       b, err := json.Marshal(&tx)
+                       if err != nil {
+                               t.Errorf("marshaling of %s failed: %s", &tx, err)
+                               continue
+                       }
+                       var rx Int
+                       if err := json.Unmarshal(b, &rx); err != nil {
+                               t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+                               continue
+                       }
+                       if rx.Cmp(&tx) != 0 {
+                               t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+                       }
+               }
+       }
+}
+
+func TestIntXMLEncoding(t *testing.T) {
+       for _, test := range encodingTests {
+               for _, sign := range []string{"", "+", "-"} {
+                       x := sign + test
+                       var tx Int
+                       tx.SetString(x, 0)
+                       b, err := xml.Marshal(&tx)
+                       if err != nil {
+                               t.Errorf("marshaling of %s failed: %s", &tx, err)
+                               continue
+                       }
+                       var rx Int
+                       if err := xml.Unmarshal(b, &rx); err != nil {
+                               t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+                               continue
+                       }
+                       if rx.Cmp(&tx) != 0 {
+                               t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+                       }
+               }
+       }
+}
index 6545bc17ed36734a7d8189739514eacc33cef07a..79cf6e07f7fa1de3e8cdf25d2b1980bc168c7ba3 100644 (file)
@@ -2,31 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package big implements multi-precision arithmetic (big numbers).
-// The following numeric types are supported:
-//
-//   Int    signed integers
-//   Rat    rational numbers
-//   Float  floating-point numbers
-//
-// Methods are typically of the form:
-//
-//   func (z *T) Unary(x *T) *T        // z = op x
-//   func (z *T) Binary(x, y *T) *T    // z = x op y
-//   func (x *T) M() T1                // v = x.M()
-//
-// with T one of Int, Rat, or Float. For unary and binary operations, the
-// result is the receiver (usually named z in that case); if it is one of
-// the operands x or y it may be overwritten (and its memory reused).
-// To enable chaining of operations, the result is also returned. Methods
-// returning a result other than *Int, *Rat, or *Float take an operand as
-// the receiver (usually named x in that case).
-//
-package big
+// This file implements unsigned multi-precision integers (natural
+// numbers). They are the building blocks for the implementation
+// of signed integers, rationals, and floating-point numbers.
 
-// This file contains operations on unsigned multi-precision integers.
-// These are the building blocks for the operations on signed integers
-// and rationals.
+package big
 
 import "math/rand"
 
@@ -216,29 +196,42 @@ func basicMul(z, x, y nat) {
        }
 }
 
-// montgomery computes x*y*2^(-n*_W) mod m,
-// assuming k = -1/m mod 2^_W.
+// montgomery computes z mod m = x*y*2**(-n*_W) mod m,
+// assuming k = -1/m mod 2**_W.
 // z is used for storing the result which is returned;
 // z must not alias x, y or m.
+// See Gueron, "Efficient Software Implementations of Modular Exponentiation".
+// https://eprint.iacr.org/2011/239.pdf
+// In the terminology of that paper, this is an "Almost Montgomery Multiplication":
+// x and y are required to satisfy 0 <= z < 2**(n*_W) and then the result
+// z is guaranteed to satisfy 0 <= z < 2**(n*_W), but it may not be < m.
 func (z nat) montgomery(x, y, m nat, k Word, n int) nat {
-       var c1, c2 Word
+       // This code assumes x, y, m are all the same length, n.
+       // (required by addMulVVW and the for loop).
+       // It also assumes that x, y are already reduced mod m,
+       // or else the result will not be properly reduced.
+       if len(x) != n || len(y) != n || len(m) != n {
+               panic("math/big: mismatched montgomery number lengths")
+       }
        z = z.make(n)
        z.clear()
+       var c Word
        for i := 0; i < n; i++ {
                d := y[i]
-               c1 += addMulVVW(z, x, d)
+               c2 := addMulVVW(z, x, d)
                t := z[0] * k
-               c2 = addMulVVW(z, m, t)
-
+               c3 := addMulVVW(z, m, t)
                copy(z, z[1:])
-               z[n-1] = c1 + c2
-               if z[n-1] < c1 {
-                       c1 = 1
+               cx := c + c2
+               cy := cx + c3
+               z[n-1] = cy
+               if cx < c2 || cy < c3 {
+                       c = 1
                } else {
-                       c1 = 0
+                       c = 0
                }
        }
-       if c1 != 0 {
+       if c != 0 {
                subVV(z, z, m)
        }
        return z
@@ -1063,26 +1056,22 @@ func (z nat) expNNWindowed(x, y, m nat) nat {
 // expNNMontgomery calculates x**y mod m using a fixed, 4-bit window.
 // Uses Montgomery representation.
 func (z nat) expNNMontgomery(x, y, m nat) nat {
-       var zz, one, rr, RR nat
-
        numWords := len(m)
 
        // We want the lengths of x and m to be equal.
+       // It is OK if x >= m as long as len(x) == len(m).
        if len(x) > numWords {
-               _, rr = rr.div(rr, x, m)
-       } else if len(x) < numWords {
-               rr = rr.make(numWords)
-               rr.clear()
-               for i := range x {
-                       rr[i] = x[i]
-               }
-       } else {
-               rr = x
+               _, x = nat(nil).div(nil, x, m)
+               // Note: now len(x) <= numWords, not guaranteed ==.
+       }
+       if len(x) < numWords {
+               rr := make(nat, numWords)
+               copy(rr, x)
+               x = rr
        }
-       x = rr
 
        // Ideally the precomputations would be performed outside, and reused
-       // k0 = -mˆ-1 mod 2ˆ_W. Algorithm from: Dumas, J.G. "On Newton–Raphson
+       // k0 = -m**-1 mod 2**_W. Algorithm from: Dumas, J.G. "On Newton–Raphson
        // Iteration for Multiplicative Inverses Modulo Prime Powers".
        k0 := 2 - m[0]
        t := m[0] - 1
@@ -1092,9 +1081,9 @@ func (z nat) expNNMontgomery(x, y, m nat) nat {
        }
        k0 = -k0
 
-       // RR = 2ˆ(2*_W*len(m)) mod m
-       RR = RR.setWord(1)
-       zz = zz.shl(RR, uint(2*numWords*_W))
+       // RR = 2**(2*_W*len(m)) mod m
+       RR := nat(nil).setWord(1)
+       zz := nat(nil).shl(RR, uint(2*numWords*_W))
        _, RR = RR.div(RR, zz, m)
        if len(RR) < numWords {
                zz = zz.make(numWords)
@@ -1102,8 +1091,7 @@ func (z nat) expNNMontgomery(x, y, m nat) nat {
                RR = zz
        }
        // one = 1, with equal length to that of m
-       one = one.make(numWords)
-       one.clear()
+       one := make(nat, numWords)
        one[0] = 1
 
        const n = 4
@@ -1138,12 +1126,32 @@ func (z nat) expNNMontgomery(x, y, m nat) nat {
        }
        // convert to regular number
        zz = zz.montgomery(z, one, m, k0, numWords)
+
+       // One last reduction, just in case.
+       // See golang.org/issue/13907.
+       if zz.cmp(m) >= 0 {
+               // Common case is m has high bit set; in that case,
+               // since zz is the same length as m, there can be just
+               // one multiple of m to remove. Just subtract.
+               // We think that the subtract should be sufficient in general,
+               // so do that unconditionally, but double-check,
+               // in case our beliefs are wrong.
+               // The div is not expected to be reached.
+               zz = zz.sub(zz, m)
+               if zz.cmp(m) >= 0 {
+                       _, zz = nat(nil).div(nil, zz, m)
+               }
+       }
+
        return zz.norm()
 }
 
-// probablyPrime performs reps Miller-Rabin tests to check whether n is prime.
-// If it returns true, n is prime with probability 1 - 1/4^reps.
-// If it returns false, n is not prime.
+// probablyPrime performs n Miller-Rabin tests to check whether x is prime.
+// If x is prime, it returns true.
+// If x is not prime, it returns false with probability at least 1 - ¼ⁿ.
+//
+// It is not suitable for judging primes that an adversary may have crafted
+// to fool this test.
 func (n nat) probablyPrime(reps int) bool {
        if len(n) == 0 {
                return false
index 7ac3cb8a8468f9554eec86c4bafeea8f42cdfd1a..563ccb30523adab0c1f4982cc40bc1e67ea2944b 100644 (file)
@@ -158,7 +158,7 @@ var mulRangesN = []struct {
 
 func TestMulRangeN(t *testing.T) {
        for i, r := range mulRangesN {
-               prod := nat(nil).mulRange(r.a, r.b).decimalString()
+               prod := string(nat(nil).mulRange(r.a, r.b).utoa(10))
                if prod != r.prod {
                        t.Errorf("#%d: got %s; want %s", i, prod, r.prod)
                }
@@ -326,7 +326,7 @@ func TestTrailingZeroBits(t *testing.T) {
        for i := uint(0); i <= 3*_W; i++ {
                n := y.trailingZeroBits()
                if n != i {
-                       t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.hexString(), n, i)
+                       t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.utoa(16), n, i)
                }
                y = y.shl(y, 1)
        }
@@ -341,25 +341,57 @@ var montgomeryTests = []struct {
                "0xffffffffffffffffffffffffffffffffffffffffffffffffe",
                "0xffffffffffffffffffffffffffffffffffffffffffffffffe",
                "0xfffffffffffffffffffffffffffffffffffffffffffffffff",
-               0x0000000000000000,
-               "0xffffffffffffffffffffffffffffffffffffffffff",
-               "0xffffffffffffffffffffffffffffffffff",
+               1,
+               "0x1000000000000000000000000000000000000000000",
+               "0x10000000000000000000000000000000000",
        },
        {
-               "0x0000000080000000",
-               "0x00000000ffffffff",
+               "0x000000000ffffff5",
+               "0x000000000ffffff0",
                "0x0000000010000001",
                0xff0000000fffffff,
-               "0x0000000088000000",
-               "0x0000000007800001",
+               "0x000000000bfffff4",
+               "0x0000000003400001",
+       },
+       {
+               "0x0000000080000000",
+               "0x00000000ffffffff",
+               "0x1000000000000001",
+               0xfffffffffffffff,
+               "0x0800000008000001",
+               "0x0800000008000001",
+       },
+       {
+               "0x0000000080000000",
+               "0x0000000080000000",
+               "0xffffffff00000001",
+               0xfffffffeffffffff,
+               "0xbfffffff40000001",
+               "0xbfffffff40000001",
+       },
+       {
+               "0x0000000080000000",
+               "0x0000000080000000",
+               "0x00ffffff00000001",
+               0xfffffeffffffff,
+               "0xbfffff40000001",
+               "0xbfffff40000001",
+       },
+       {
+               "0x0000000080000000",
+               "0x0000000080000000",
+               "0x0000ffff00000001",
+               0xfffeffffffff,
+               "0xbfff40000001",
+               "0xbfff40000001",
        },
        {
-               "0xffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
-               "0xffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc",
+               "0x3321ffffffffffffffffffffffffffff00000000000022222623333333332bbbb888c0",
+               "0x3321ffffffffffffffffffffffffffff00000000000022222623333333332bbbb888c0",
                "0x33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
                0xdecc8f1249812adf,
-               "0x22bb05b6d95eaaeca2bb7c05e51f807bce9064b5fbad177161695e4558f9474e91cd79",
-               "0x14beb58d230f85b6d95eaaeca2bb7c05e51f807bce9064b5fb45669afa695f228e48cd",
+               "0x04eb0e11d72329dc0915f86784820fc403275bf2f6620a20e0dd344c5cd0875e50deb5",
+               "0x0d7144739a7d8e11d72329dc0915f86784820fc403275bf2f61ed96f35dd34dbb3d6a0",
        },
        {
                "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
@@ -372,10 +404,27 @@ var montgomeryTests = []struct {
 }
 
 func TestMontgomery(t *testing.T) {
+       one := NewInt(1)
+       _B := new(Int).Lsh(one, _W)
        for i, test := range montgomeryTests {
                x := natFromString(test.x)
                y := natFromString(test.y)
                m := natFromString(test.m)
+               for len(x) < len(m) {
+                       x = append(x, 0)
+               }
+               for len(y) < len(m) {
+                       y = append(y, 0)
+               }
+
+               if x.cmp(m) > 0 {
+                       _, r := nat(nil).div(nil, x, m)
+                       t.Errorf("#%d: x > m (0x%s > 0x%s; use 0x%s)", i, x.utoa(16), m.utoa(16), r.utoa(16))
+               }
+               if y.cmp(m) > 0 {
+                       _, r := nat(nil).div(nil, x, m)
+                       t.Errorf("#%d: y > m (0x%s > 0x%s; use 0x%s)", i, y.utoa(16), m.utoa(16), r.utoa(16))
+               }
 
                var out nat
                if _W == 32 {
@@ -384,11 +433,31 @@ func TestMontgomery(t *testing.T) {
                        out = natFromString(test.out64)
                }
 
-               k0 := Word(test.k0 & _M) // mask k0 to ensure that it fits for 32-bit systems.
+               // t.Logf("#%d: len=%d\n", i, len(m))
+
+               // check output in table
+               xi := &Int{abs: x}
+               yi := &Int{abs: y}
+               mi := &Int{abs: m}
+               p := new(Int).Mod(new(Int).Mul(xi, new(Int).Mul(yi, new(Int).ModInverse(new(Int).Lsh(one, uint(len(m))*_W), mi))), mi)
+               if out.cmp(p.abs.norm()) != 0 {
+                       t.Errorf("#%d: out in table=0x%s, computed=0x%s", i, out.utoa(16), p.abs.norm().utoa(16))
+               }
+
+               // check k0 in table
+               k := new(Int).Mod(&Int{abs: m}, _B)
+               k = new(Int).Sub(_B, k)
+               k = new(Int).Mod(k, _B)
+               k0 := Word(new(Int).ModInverse(k, _B).Uint64())
+               if k0 != Word(test.k0) {
+                       t.Errorf("#%d: k0 in table=%#x, computed=%#x\n", i, test.k0, k0)
+               }
+
+               // check montgomery with correct k0 produces correct output
                z := nat(nil).montgomery(x, y, m, k0, len(m))
                z = z.norm()
                if z.cmp(out) != 0 {
-                       t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
+                       t.Errorf("#%d: got 0x%s want 0x%s", i, z.utoa(16), out.utoa(16))
                }
        }
 }
@@ -414,6 +483,12 @@ var expNNTests = []struct {
                "29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
                "23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291",
        },
+       {
+               "11521922904531591643048817447554701904414021819823889996244743037378330903763518501116638828335352811871131385129455853417360623007349090150042001944696604737499160174391019030572483602867266711107136838523916077674888297896995042968746762200926853379",
+               "426343618817810911523",
+               "444747819283133684179",
+               "42",
+       },
 }
 
 func TestExpNN(t *testing.T) {
@@ -429,7 +504,7 @@ func TestExpNN(t *testing.T) {
 
                z := nat(nil).expNN(x, y, m)
                if z.cmp(out) != 0 {
-                       t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
+                       t.Errorf("#%d got %s want %s", i, z.utoa(10), out.utoa(10))
                }
        }
 }
@@ -486,7 +561,7 @@ var fiboNums = []string{
 func TestFibo(t *testing.T) {
        for i, want := range fiboNums {
                n := i * 10
-               got := fibo(n).decimalString()
+               got := string(fibo(n).utoa(10))
                if got != want {
                        t.Errorf("fibo(%d) failed: got %s want %s", n, got, want)
                }
index 022dcfe38c8d363326a9acef69ff5c7089664adb..d2ce667fb602c5c695414e1219dbf166fb4719f1 100644 (file)
@@ -14,6 +14,11 @@ import (
        "sync"
 )
 
+const digits = "0123456789abcdefghijklmnopqrstuvwxyz"
+
+// Note: MaxBase = len(digits), but it must remain a rune constant
+//       for API compatibility.
+
 // MaxBase is the largest number base accepted for string conversions.
 const MaxBase = 'z' - 'a' + 10 + 1
 
@@ -229,56 +234,45 @@ func (z nat) scan(r io.ByteScanner, base int, fracOk bool) (res nat, b, count in
        return
 }
 
-// Character sets for string conversion.
-const (
-       lowercaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz"
-       uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-)
-
-// decimalString returns a decimal representation of x.
-// It calls x.string with the charset "0123456789".
-func (x nat) decimalString() string {
-       return x.string(lowercaseDigits[:10])
+// utoa converts x to an ASCII representation in the given base;
+// base must be between 2 and MaxBase, inclusive.
+func (x nat) utoa(base int) []byte {
+       return x.itoa(false, base)
 }
 
-// hexString returns a hexadecimal representation of x.
-// It calls x.string with the charset "0123456789abcdef".
-func (x nat) hexString() string {
-       return x.string(lowercaseDigits[:16])
-}
+// itoa is like utoa but it prepends a '-' if neg && x != 0.
+func (x nat) itoa(neg bool, base int) []byte {
+       if base < 2 || base > MaxBase {
+               panic("invalid base")
+       }
 
-// string converts x to a string using digits from a charset; a digit with
-// value d is represented by charset[d]. The conversion base is determined
-// by len(charset), which must be >= 2 and <= 256.
-func (x nat) string(charset string) string {
-       b := Word(len(charset))
-
-       // special cases
-       switch {
-       case b < 2 || b > 256:
-               panic("invalid character set length")
-       case len(x) == 0:
-               return string(charset[0])
+       // x == 0
+       if len(x) == 0 {
+               return []byte("0")
        }
+       // len(x) > 0
 
        // allocate buffer for conversion
-       i := int(float64(x.bitLen())/math.Log2(float64(b))) + 1 // off by one at most
+       i := int(float64(x.bitLen())/math.Log2(float64(base))) + 1 // off by 1 at most
+       if neg {
+               i++
+       }
        s := make([]byte, i)
 
        // convert power of two and non power of two bases separately
-       if b == b&-b {
-               // shift is base-b digit size in bits
+       if b := Word(base); b == b&-b {
+               // shift is base b digit size in bits
                shift := trailingZeroBits(b) // shift > 0 because b >= 2
-               mask := Word(1)<<shift - 1
-               w := x[0]
+               mask := Word(1<<shift - 1)
+               w := x[0]         // current word
                nbits := uint(_W) // number of unprocessed bits in w
 
-               // convert less-significant words
+               // convert less-significant words (include leading zeros)
                for k := 1; k < len(x); k++ {
                        // convert full digits
                        for nbits >= shift {
                                i--
-                               s[i] = charset[w&mask]
+                               s[i] = digits[w&mask]
                                w >>= shift
                                nbits -= shift
                        }
@@ -289,10 +283,10 @@ func (x nat) string(charset string) string {
                                w = x[k]
                                nbits = _W
                        } else {
-                               // partial digit in current (k-1) and next (k) word
+                               // partial digit in current word w (== x[k-1]) and next word x[k]
                                w |= x[k] << nbits
                                i--
-                               s[i] = charset[w&mask]
+                               s[i] = digits[w&mask]
 
                                // advance
                                w = x[k] >> (shift - nbits)
@@ -300,12 +294,11 @@ func (x nat) string(charset string) string {
                        }
                }
 
-               // convert digits of most-significant word (omit leading zeros)
-               for nbits >= 0 && w != 0 {
+               // convert digits of most-significant word (omit leading zeros)
+               for w != 0 {
                        i--
-                       s[i] = charset[w&mask]
+                       s[i] = digits[w&mask]
                        w >>= shift
-                       nbits -= shift
                }
 
        } else {
@@ -319,18 +312,23 @@ func (x nat) string(charset string) string {
                q := nat(nil).set(x)
 
                // convert q to string s in base b
-               q.convertWords(s, charset, b, ndigits, bb, table)
+               q.convertWords(s, b, ndigits, bb, table)
 
                // strip leading zeros
                // (x != 0; thus s must contain at least one non-zero digit
                // and the loop will terminate)
                i = 0
-               for zero := charset[0]; s[i] == zero; {
+               for s[i] == '0' {
                        i++
                }
        }
 
-       return string(s[i:])
+       if neg {
+               i--
+               s[i] = '-'
+       }
+
+       return s[i:]
 }
 
 // Convert words of q to base b digits in s. If q is large, it is recursively "split in half"
@@ -349,7 +347,7 @@ func (x nat) string(charset string) string {
 // ~30x for 20000 digits. Use nat_test.go's BenchmarkLeafSize tests to optimize leafSize for
 // specific hardware.
 //
-func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word, table []divisor) {
+func (q nat) convertWords(s []byte, b Word, ndigits int, bb Word, table []divisor) {
        // split larger blocks recursively
        if table != nil {
                // len(q) > leafSize > 0
@@ -374,8 +372,8 @@ func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word
 
                        // convert subblocks and collect results in s[:h] and s[h:]
                        h := len(s) - table[index].ndigits
-                       r.convertWords(s[h:], charset, b, ndigits, bb, table[0:index])
-                       s = s[:h] // == q.convertWords(s, charset, b, ndigits, bb, table[0:index+1])
+                       r.convertWords(s[h:], b, ndigits, bb, table[0:index])
+                       s = s[:h] // == q.convertWords(s, b, ndigits, bb, table[0:index+1])
                }
        }
 
@@ -393,7 +391,7 @@ func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word
                                // this appears to be faster for BenchmarkString10000Base10
                                // and smaller strings (but a bit slower for larger ones)
                                t := r / 10
-                               s[i] = charset[r-t<<3-t-t] // TODO(gri) replace w/ t*10 once compiler produces better code
+                               s[i] = '0' + byte(r-t<<3-t-t) // TODO(gri) replace w/ t*10 once compiler produces better code
                                r = t
                        }
                }
@@ -403,17 +401,16 @@ func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word
                        q, r = q.divW(q, bb)
                        for j := 0; j < ndigits && i > 0; j++ {
                                i--
-                               s[i] = charset[r%b]
+                               s[i] = digits[r%b]
                                r /= b
                        }
                }
        }
 
-       // prepend high-order zeroes
-       zero := charset[0]
-       for i > 0 { // while need more leading zeroes
+       // prepend high-order zeros
+       for i > 0 { // while need more leading zeros
                i--
-               s[i] = zero
+               s[i] = '0'
        }
 }
 
@@ -425,7 +422,7 @@ var leafSize int = 8 // number of Word-size binary values treat as a monolithic
 
 type divisor struct {
        bbb     nat // divisor
-       nbits   int // bit length of divisor (discounting leading zeroes) ~= log2(bbb)
+       nbits   int // bit length of divisor (discounting leading zeros) ~= log2(bbb)
        ndigits int // digit length of divisor in terms of output base digits
 }
 
index f321fbc2df0884b18f4b1e767383f7be9d599b2c..028e5a858eb98c4e7054abb709bdb376a1de9a3b 100644 (file)
@@ -5,20 +5,19 @@
 package big
 
 import (
+       "bytes"
        "io"
        "strings"
        "testing"
 )
 
-func toString(x nat, charset string) string {
-       base := len(charset)
-
+func itoa(x nat, base int) []byte {
        // special cases
        switch {
        case base < 2:
                panic("illegal base")
        case len(x) == 0:
-               return string(charset[0])
+               return []byte("0")
        }
 
        // allocate buffer for conversion
@@ -33,54 +32,53 @@ func toString(x nat, charset string) string {
                i--
                var r Word
                q, r = q.divW(q, Word(base))
-               s[i] = charset[r]
+               s[i] = digits[r]
        }
 
-       return string(s[i:])
+       return s[i:]
 }
 
 var strTests = []struct {
        x nat    // nat value to be converted
-       c string // conversion charset
+       b int    // conversion base
        s string // expected result
 }{
-       {nil, "01", "0"},
-       {nat{1}, "01", "1"},
-       {nat{0xc5}, "01", "11000101"},
-       {nat{03271}, lowercaseDigits[:8], "3271"},
-       {nat{10}, lowercaseDigits[:10], "10"},
-       {nat{1234567890}, uppercaseDigits[:10], "1234567890"},
-       {nat{0xdeadbeef}, lowercaseDigits[:16], "deadbeef"},
-       {nat{0xdeadbeef}, uppercaseDigits[:16], "DEADBEEF"},
-       {nat{0x229be7}, lowercaseDigits[:17], "1a2b3c"},
-       {nat{0x309663e6}, uppercaseDigits[:32], "O9COV6"},
+       {nil, 2, "0"},
+       {nat{1}, 2, "1"},
+       {nat{0xc5}, 2, "11000101"},
+       {nat{03271}, 8, "3271"},
+       {nat{10}, 10, "10"},
+       {nat{1234567890}, 10, "1234567890"},
+       {nat{0xdeadbeef}, 16, "deadbeef"},
+       {nat{0x229be7}, 17, "1a2b3c"},
+       {nat{0x309663e6}, 32, "o9cov6"},
 }
 
 func TestString(t *testing.T) {
-       // test invalid character set explicitly
+       // test invalid base explicitly
        var panicStr string
        func() {
                defer func() {
                        panicStr = recover().(string)
                }()
-               natOne.string("0")
+               natOne.utoa(1)
        }()
-       if panicStr != "invalid character set length" {
-               t.Errorf("expected panic for invalid character set")
+       if panicStr != "invalid base" {
+               t.Errorf("expected panic for invalid base")
        }
 
        for _, a := range strTests {
-               s := a.x.string(a.c)
+               s := string(a.x.utoa(a.b))
                if s != a.s {
                        t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s)
                }
 
-               x, b, _, err := nat(nil).scan(strings.NewReader(a.s), len(a.c), false)
+               x, b, _, err := nat(nil).scan(strings.NewReader(a.s), a.b, false)
                if x.cmp(a.x) != 0 {
                        t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
                }
-               if b != len(a.c) {
-                       t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, len(a.c))
+               if b != a.b {
+                       t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.b)
                }
                if err != nil {
                        t.Errorf("scan%+v\n\tgot error = %s", a, err)
@@ -236,7 +234,7 @@ func TestScanPi(t *testing.T) {
        if err != nil {
                t.Errorf("scanning pi: %s", err)
        }
-       if s := z.decimalString(); s != pi {
+       if s := string(z.utoa(10)); s != pi {
                t.Errorf("scanning pi: got %s", s)
        }
 }
@@ -265,12 +263,12 @@ func BenchmarkScanPi(b *testing.B) {
 func BenchmarkStringPiParallel(b *testing.B) {
        var x nat
        x, _, _, _ = x.scan(strings.NewReader(pi), 0, false)
-       if x.decimalString() != pi {
+       if string(x.utoa(10)) != pi {
                panic("benchmark incorrect: conversion failed")
        }
        b.RunParallel(func(pb *testing.PB) {
                for pb.Next() {
-                       x.decimalString()
+                       x.utoa(10)
                }
        })
 }
@@ -304,15 +302,14 @@ func ScanHelper(b *testing.B, base int, x, y Word) {
        var z nat
        z = z.expWW(x, y)
 
-       var s string
-       s = z.string(lowercaseDigits[:base])
-       if t := toString(z, lowercaseDigits[:base]); t != s {
+       s := z.utoa(base)
+       if t := itoa(z, base); !bytes.Equal(s, t) {
                b.Fatalf("scanning: got %s; want %s", s, t)
        }
        b.StartTimer()
 
        for i := 0; i < b.N; i++ {
-               z.scan(strings.NewReader(s), base, false)
+               z.scan(bytes.NewReader(s), base, false)
        }
 }
 
@@ -344,11 +341,11 @@ func StringHelper(b *testing.B, base int, x, y Word) {
        b.StopTimer()
        var z nat
        z = z.expWW(x, y)
-       z.string(lowercaseDigits[:base]) // warm divisor cache
+       z.utoa(base) // warm divisor cache
        b.StartTimer()
 
        for i := 0; i < b.N; i++ {
-               _ = z.string(lowercaseDigits[:base])
+               _ = z.utoa(base)
        }
 }
 
@@ -372,7 +369,7 @@ func BenchmarkLeafSize16(b *testing.B) { LeafSizeHelper(b, 10, 16) }
 func BenchmarkLeafSize32(b *testing.B) { LeafSizeHelper(b, 10, 32) } // try some large lengths
 func BenchmarkLeafSize64(b *testing.B) { LeafSizeHelper(b, 10, 64) }
 
-func LeafSizeHelper(b *testing.B, base Word, size int) {
+func LeafSizeHelper(b *testing.B, base, size int) {
        b.StopTimer()
        originalLeafSize := leafSize
        resetTable(cacheBase10.table[:])
@@ -382,12 +379,12 @@ func LeafSizeHelper(b *testing.B, base Word, size int) {
        for d := 1; d <= 10000; d *= 10 {
                b.StopTimer()
                var z nat
-               z = z.expWW(base, Word(d))           // build target number
-               _ = z.string(lowercaseDigits[:base]) // warm divisor cache
+               z = z.expWW(Word(base), Word(d)) // build target number
+               _ = z.utoa(base)                 // warm divisor cache
                b.StartTimer()
 
                for i := 0; i < b.N; i++ {
-                       _ = z.string(lowercaseDigits[:base])
+                       _ = z.utoa(base)
                }
        }
 
@@ -408,13 +405,13 @@ func resetTable(table []divisor) {
 }
 
 func TestStringPowers(t *testing.T) {
-       var b, p Word
-       for b = 2; b <= 16; b++ {
+       var p Word
+       for b := 2; b <= 16; b++ {
                for p = 0; p <= 512; p++ {
-                       x := nat(nil).expWW(b, p)
-                       xs := x.string(lowercaseDigits[:b])
-                       xs2 := toString(x, lowercaseDigits[:b])
-                       if xs != xs2 {
+                       x := nat(nil).expWW(Word(b), p)
+                       xs := x.utoa(b)
+                       xs2 := itoa(x, b)
+                       if !bytes.Equal(xs, xs2) {
                                t.Errorf("failed at %d ** %d in base %d: %s != %s", b, p, b, xs, xs2)
                        }
                }
index fb16f18a964e7121dc3cb635887a6a8d37c3628b..2cd9ed09388aeb3dd8a6211217a7aa843ad7f2ea 100644 (file)
@@ -7,8 +7,6 @@
 package big
 
 import (
-       "encoding/binary"
-       "errors"
        "fmt"
        "math"
 )
@@ -510,61 +508,3 @@ func (z *Rat) Quo(x, y *Rat) *Rat {
        z.a.neg = a.neg != b.neg
        return z.norm()
 }
-
-// Gob codec version. Permits backward-compatible changes to the encoding.
-const ratGobVersion byte = 1
-
-// GobEncode implements the gob.GobEncoder interface.
-func (x *Rat) GobEncode() ([]byte, error) {
-       if x == nil {
-               return nil, nil
-       }
-       buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b.abs))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
-       i := x.b.abs.bytes(buf)
-       j := x.a.abs.bytes(buf[:i])
-       n := i - j
-       if int(uint32(n)) != n {
-               // this should never happen
-               return nil, errors.New("Rat.GobEncode: numerator too large")
-       }
-       binary.BigEndian.PutUint32(buf[j-4:j], uint32(n))
-       j -= 1 + 4
-       b := ratGobVersion << 1 // make space for sign bit
-       if x.a.neg {
-               b |= 1
-       }
-       buf[j] = b
-       return buf[j:], nil
-}
-
-// GobDecode implements the gob.GobDecoder interface.
-func (z *Rat) GobDecode(buf []byte) error {
-       if len(buf) == 0 {
-               // Other side sent a nil or default value.
-               *z = Rat{}
-               return nil
-       }
-       b := buf[0]
-       if b>>1 != ratGobVersion {
-               return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1)
-       }
-       const j = 1 + 4
-       i := j + binary.BigEndian.Uint32(buf[j-4:j])
-       z.a.neg = b&1 != 0
-       z.a.abs = z.a.abs.setBytes(buf[j:i])
-       z.b.abs = z.b.abs.setBytes(buf[i:])
-       return nil
-}
-
-// MarshalText implements the encoding.TextMarshaler interface.
-func (r *Rat) MarshalText() (text []byte, err error) {
-       return []byte(r.RatString()), nil
-}
-
-// UnmarshalText implements the encoding.TextUnmarshaler interface.
-func (r *Rat) UnmarshalText(text []byte) error {
-       if _, ok := r.SetString(string(text)); !ok {
-               return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text)
-       }
-       return nil
-}
index 012d0c47ec4fb857553e9bb6de246f102dfd8348..3a06fca3c347f636369d861bfa528114f5777478 100644 (file)
@@ -5,10 +5,6 @@
 package big
 
 import (
-       "bytes"
-       "encoding/gob"
-       "encoding/json"
-       "encoding/xml"
        "math"
        "testing"
 )
@@ -280,116 +276,6 @@ func TestRatSetFrac64Rat(t *testing.T) {
        }
 }
 
-func TestRatGobEncoding(t *testing.T) {
-       var medium bytes.Buffer
-       enc := gob.NewEncoder(&medium)
-       dec := gob.NewDecoder(&medium)
-       for _, test := range encodingTests {
-               medium.Reset() // empty buffer for each test case (in case of failures)
-               var tx Rat
-               tx.SetString(test + ".14159265")
-               if err := enc.Encode(&tx); err != nil {
-                       t.Errorf("encoding of %s failed: %s", &tx, err)
-               }
-               var rx Rat
-               if err := dec.Decode(&rx); err != nil {
-                       t.Errorf("decoding of %s failed: %s", &tx, err)
-               }
-               if rx.Cmp(&tx) != 0 {
-                       t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx)
-               }
-       }
-}
-
-// Sending a nil Rat pointer (inside a slice) on a round trip through gob should yield a zero.
-// TODO: top-level nils.
-func TestGobEncodingNilRatInSlice(t *testing.T) {
-       buf := new(bytes.Buffer)
-       enc := gob.NewEncoder(buf)
-       dec := gob.NewDecoder(buf)
-
-       var in = make([]*Rat, 1)
-       err := enc.Encode(&in)
-       if err != nil {
-               t.Errorf("gob encode failed: %q", err)
-       }
-       var out []*Rat
-       err = dec.Decode(&out)
-       if err != nil {
-               t.Fatalf("gob decode failed: %q", err)
-       }
-       if len(out) != 1 {
-               t.Fatalf("wrong len; want 1 got %d", len(out))
-       }
-       var zero Rat
-       if out[0].Cmp(&zero) != 0 {
-               t.Errorf("transmission of (*Int)(nill) failed: got %s want 0", out)
-       }
-}
-
-var ratNums = []string{
-       "-141592653589793238462643383279502884197169399375105820974944592307816406286",
-       "-1415926535897932384626433832795028841971",
-       "-141592653589793",
-       "-1",
-       "0",
-       "1",
-       "141592653589793",
-       "1415926535897932384626433832795028841971",
-       "141592653589793238462643383279502884197169399375105820974944592307816406286",
-}
-
-var ratDenoms = []string{
-       "1",
-       "718281828459045",
-       "7182818284590452353602874713526624977572",
-       "718281828459045235360287471352662497757247093699959574966967627724076630353",
-}
-
-func TestRatJSONEncoding(t *testing.T) {
-       for _, num := range ratNums {
-               for _, denom := range ratDenoms {
-                       var tx Rat
-                       tx.SetString(num + "/" + denom)
-                       b, err := json.Marshal(&tx)
-                       if err != nil {
-                               t.Errorf("marshaling of %s failed: %s", &tx, err)
-                               continue
-                       }
-                       var rx Rat
-                       if err := json.Unmarshal(b, &rx); err != nil {
-                               t.Errorf("unmarshaling of %s failed: %s", &tx, err)
-                               continue
-                       }
-                       if rx.Cmp(&tx) != 0 {
-                               t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
-                       }
-               }
-       }
-}
-
-func TestRatXMLEncoding(t *testing.T) {
-       for _, num := range ratNums {
-               for _, denom := range ratDenoms {
-                       var tx Rat
-                       tx.SetString(num + "/" + denom)
-                       b, err := xml.Marshal(&tx)
-                       if err != nil {
-                               t.Errorf("marshaling of %s failed: %s", &tx, err)
-                               continue
-                       }
-                       var rx Rat
-                       if err := xml.Unmarshal(b, &rx); err != nil {
-                               t.Errorf("unmarshaling of %s failed: %s", &tx, err)
-                               continue
-                       }
-                       if rx.Cmp(&tx) != 0 {
-                               t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
-                       }
-               }
-       }
-}
-
 func TestIssue2379(t *testing.T) {
        // 1) no aliasing
        q := NewRat(3, 2)
index 961ff649a50c816fb20a75164fc78f5c318516e4..4566ff4e39d74b289413da80bd288e8044fa7ca1 100644 (file)
@@ -188,11 +188,15 @@ func scanExponent(r io.ByteScanner, binExpOk bool) (exp int64, base int, err err
 
 // String returns a string representation of x in the form "a/b" (even if b == 1).
 func (x *Rat) String() string {
-       s := "/1"
+       var buf []byte
+       buf = x.a.Append(buf, 10)
+       buf = append(buf, '/')
        if len(x.b.abs) != 0 {
-               s = "/" + x.b.abs.decimalString()
+               buf = x.b.Append(buf, 10)
+       } else {
+               buf = append(buf, '1')
        }
-       return x.a.String() + s
+       return string(buf)
 }
 
 // RatString returns a string representation of x in the form "a/b" if b != 1,
@@ -208,12 +212,17 @@ func (x *Rat) RatString() string {
 // digits of precision after the decimal point. The last digit is rounded to
 // nearest, with halves rounded away from zero.
 func (x *Rat) FloatString(prec int) string {
+       var buf []byte
+
        if x.IsInt() {
-               s := x.a.String()
+               buf = x.a.Append(buf, 10)
                if prec > 0 {
-                       s += "." + strings.Repeat("0", prec)
+                       buf = append(buf, '.')
+                       for i := prec; i > 0; i-- {
+                               buf = append(buf, '0')
+                       }
                }
-               return s
+               return string(buf)
        }
        // x.b.abs != 0
 
@@ -237,16 +246,19 @@ func (x *Rat) FloatString(prec int) string {
                }
        }
 
-       s := q.decimalString()
        if x.a.neg {
-               s = "-" + s
+               buf = append(buf, '-')
        }
+       buf = append(buf, q.utoa(10)...) // itoa ignores sign if q == 0
 
        if prec > 0 {
-               rs := r.decimalString()
-               leadingZeros := prec - len(rs)
-               s += "." + strings.Repeat("0", leadingZeros) + rs
+               buf = append(buf, '.')
+               rs := r.utoa(10)
+               for i := prec - len(rs); i > 0; i-- {
+                       buf = append(buf, '0')
+               }
+               buf = append(buf, rs...)
        }
 
-       return s
+       return string(buf)
 }
diff --git a/libgo/go/math/big/ratmarsh.go b/libgo/go/math/big/ratmarsh.go
new file mode 100644 (file)
index 0000000..b82e8d4
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright 2015 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.
+
+// This file implements encoding/decoding of Rats.
+
+package big
+
+import (
+       "encoding/binary"
+       "errors"
+       "fmt"
+)
+
+// Gob codec version. Permits backward-compatible changes to the encoding.
+const ratGobVersion byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+func (x *Rat) GobEncode() ([]byte, error) {
+       if x == nil {
+               return nil, nil
+       }
+       buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b.abs))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
+       i := x.b.abs.bytes(buf)
+       j := x.a.abs.bytes(buf[:i])
+       n := i - j
+       if int(uint32(n)) != n {
+               // this should never happen
+               return nil, errors.New("Rat.GobEncode: numerator too large")
+       }
+       binary.BigEndian.PutUint32(buf[j-4:j], uint32(n))
+       j -= 1 + 4
+       b := ratGobVersion << 1 // make space for sign bit
+       if x.a.neg {
+               b |= 1
+       }
+       buf[j] = b
+       return buf[j:], nil
+}
+
+// GobDecode implements the gob.GobDecoder interface.
+func (z *Rat) GobDecode(buf []byte) error {
+       if len(buf) == 0 {
+               // Other side sent a nil or default value.
+               *z = Rat{}
+               return nil
+       }
+       b := buf[0]
+       if b>>1 != ratGobVersion {
+               return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1)
+       }
+       const j = 1 + 4
+       i := j + binary.BigEndian.Uint32(buf[j-4:j])
+       z.a.neg = b&1 != 0
+       z.a.abs = z.a.abs.setBytes(buf[j:i])
+       z.b.abs = z.b.abs.setBytes(buf[i:])
+       return nil
+}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+func (x *Rat) MarshalText() (text []byte, err error) {
+       // TODO(gri): get rid of the []byte/string conversion
+       return []byte(x.RatString()), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+func (z *Rat) UnmarshalText(text []byte) error {
+       // TODO(gri): get rid of the []byte/string conversion
+       if _, ok := z.SetString(string(text)); !ok {
+               return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text)
+       }
+       return nil
+}
diff --git a/libgo/go/math/big/ratmarsh_test.go b/libgo/go/math/big/ratmarsh_test.go
new file mode 100644 (file)
index 0000000..351d109
--- /dev/null
@@ -0,0 +1,125 @@
+// Copyright 2015 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 big
+
+import (
+       "bytes"
+       "encoding/gob"
+       "encoding/json"
+       "encoding/xml"
+       "testing"
+)
+
+func TestRatGobEncoding(t *testing.T) {
+       var medium bytes.Buffer
+       enc := gob.NewEncoder(&medium)
+       dec := gob.NewDecoder(&medium)
+       for _, test := range encodingTests {
+               medium.Reset() // empty buffer for each test case (in case of failures)
+               var tx Rat
+               tx.SetString(test + ".14159265")
+               if err := enc.Encode(&tx); err != nil {
+                       t.Errorf("encoding of %s failed: %s", &tx, err)
+                       continue
+               }
+               var rx Rat
+               if err := dec.Decode(&rx); err != nil {
+                       t.Errorf("decoding of %s failed: %s", &tx, err)
+                       continue
+               }
+               if rx.Cmp(&tx) != 0 {
+                       t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx)
+               }
+       }
+}
+
+// Sending a nil Rat pointer (inside a slice) on a round trip through gob should yield a zero.
+// TODO: top-level nils.
+func TestGobEncodingNilRatInSlice(t *testing.T) {
+       buf := new(bytes.Buffer)
+       enc := gob.NewEncoder(buf)
+       dec := gob.NewDecoder(buf)
+
+       var in = make([]*Rat, 1)
+       err := enc.Encode(&in)
+       if err != nil {
+               t.Errorf("gob encode failed: %q", err)
+       }
+       var out []*Rat
+       err = dec.Decode(&out)
+       if err != nil {
+               t.Fatalf("gob decode failed: %q", err)
+       }
+       if len(out) != 1 {
+               t.Fatalf("wrong len; want 1 got %d", len(out))
+       }
+       var zero Rat
+       if out[0].Cmp(&zero) != 0 {
+               t.Fatalf("transmission of (*Int)(nil) failed: got %s want 0", out)
+       }
+}
+
+var ratNums = []string{
+       "-141592653589793238462643383279502884197169399375105820974944592307816406286",
+       "-1415926535897932384626433832795028841971",
+       "-141592653589793",
+       "-1",
+       "0",
+       "1",
+       "141592653589793",
+       "1415926535897932384626433832795028841971",
+       "141592653589793238462643383279502884197169399375105820974944592307816406286",
+}
+
+var ratDenoms = []string{
+       "1",
+       "718281828459045",
+       "7182818284590452353602874713526624977572",
+       "718281828459045235360287471352662497757247093699959574966967627724076630353",
+}
+
+func TestRatJSONEncoding(t *testing.T) {
+       for _, num := range ratNums {
+               for _, denom := range ratDenoms {
+                       var tx Rat
+                       tx.SetString(num + "/" + denom)
+                       b, err := json.Marshal(&tx)
+                       if err != nil {
+                               t.Errorf("marshaling of %s failed: %s", &tx, err)
+                               continue
+                       }
+                       var rx Rat
+                       if err := json.Unmarshal(b, &rx); err != nil {
+                               t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+                               continue
+                       }
+                       if rx.Cmp(&tx) != 0 {
+                               t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+                       }
+               }
+       }
+}
+
+func TestRatXMLEncoding(t *testing.T) {
+       for _, num := range ratNums {
+               for _, denom := range ratDenoms {
+                       var tx Rat
+                       tx.SetString(num + "/" + denom)
+                       b, err := xml.Marshal(&tx)
+                       if err != nil {
+                               t.Errorf("marshaling of %s failed: %s", &tx, err)
+                               continue
+                       }
+                       var rx Rat
+                       if err := xml.Unmarshal(b, &rx); err != nil {
+                               t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+                               continue
+                       }
+                       if rx.Cmp(&tx) != 0 {
+                               t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+                       }
+               }
+       }
+}
index f285646af7a8b9318b9decab32f93bde7dd6081b..18d9be819482504f32dfecca8b4650e7596c56c7 100644 (file)
@@ -438,8 +438,10 @@ func tolerance(a, b, e float64) bool {
                d = -d
        }
 
-       if a != 0 {
-               e = e * a
+       // note: b is correct (expected) value, a is actual value.
+       // make error tolerance a fraction of b, not a.
+       if b != 0 {
+               e = e * b
                if e < 0 {
                        e = -e
                }
@@ -460,8 +462,8 @@ func alike(a, b float64) bool {
 
 func cTolerance(a, b complex128, e float64) bool {
        d := Abs(a - b)
-       if a != 0 {
-               e = e * Abs(a)
+       if b != 0 {
+               e = e * Abs(b)
                if e < 0 {
                        e = -e
                }
index 4ef6807addc9e1feed74a8c5738d6a5bc1e4f608..276be07ae9a7ca905c05d145fcb8c4c01370d3f5 100644 (file)
@@ -40,7 +40,7 @@ import "math"
 //                       1/2
 // Im w  =  [ (r - x)/2 ]   .
 //
-// Cancellation error in r-x or r+x is avoided by using the
+// Cancelation error in r-x or r+x is avoided by using the
 // identity  2 Re w Im w  =  y.
 //
 // Note that -w is also a square root of z.  The root chosen
index 8d7b3d365a6890a753fa3cfbe906081f98cde53b..b4dcdc52a203a2b5db3a27999b26513d4cfd9a2f 100644 (file)
@@ -233,7 +233,7 @@ func expm1(x float64) float64 {
                        y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent
                        return y
                }
-               t := Float64frombits(uint64((0x3ff - k) << 52)) // 2**-k
+               t := Float64frombits(uint64(0x3ff-k) << 52) // 2**-k
                y := x - (e + t)
                y += 1
                y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent
similarity index 59%
rename from libgo/go/fmt/race_test.go
rename to libgo/go/math/floor_asm.go
index ae3147a5b000c9118782accd86d12140ffbf5bdb..28e56a5d51bd963f961134d01e8ecec42f9db234 100644 (file)
@@ -2,8 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build race
+// +build amd64 amd64p32
 
-package fmt_test
+package math
 
-const raceenabled = true
+//defined in floor_amd64.s
+func hasSSE4() bool
+
+var useSSE4 = hasSSE4()
index c20a9b22a89a761731b6adafe4a3839c1cfa5838..de7738880e6f5a10c6028e664add33d731aa2ace 100644 (file)
@@ -38,7 +38,7 @@ package math
 //                      = 1/sqrt(2) * (cos(x) + sin(x))
 //              sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4)
 //                      = 1/sqrt(2) * (sin(x) - cos(x))
-//         (To avoid cancellation, use
+//         (To avoid cancelation, use
 //              sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
 //         to compute the worse one.)
 //
@@ -188,7 +188,7 @@ func Y0(x float64) float64 {
                //             =  1/sqrt(2) * (sin(x) + cos(x))
                //     sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
                //             =  1/sqrt(2) * (sin(x) - cos(x))
-               // To avoid cancellation, use
+               // To avoid cancelation, use
                //     sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
                // to compute the worse one.
 
index 7ac186b72aa26cc0f92adf8c15e664708f54f099..c537a72eb2500703463997d93d631e6c2387f1a9 100644 (file)
@@ -39,7 +39,7 @@ package math
 //                      =  1/sqrt(2) * (sin(x) - cos(x))
 //              sin(x1) =  sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
 //                      = -1/sqrt(2) * (sin(x) + cos(x))
-//         (To avoid cancellation, use
+//         (To avoid cancelation, use
 //              sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
 //         to compute the worse one.)
 //
@@ -197,7 +197,7 @@ func Y1(x float64) float64 {
                //                 =  1/sqrt(2) * (sin(x) - cos(x))
                //         sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
                //                 = -1/sqrt(2) * (cos(x) + sin(x))
-               // To avoid cancellation, use
+               // To avoid cancelation, use
                //     sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
                // to compute the worse one.
 
index a7909eb24cdd3f5e1fb23e4db7f996b230b8152d..ffb8a00f50f0187e6cc735e8f13c53ee24619db8 100644 (file)
@@ -200,13 +200,11 @@ func Jn(n int, x float64) float64 {
                                for i := n - 1; i > 0; i-- {
                                        di := float64(i + i)
                                        a, b = b, b*di/x-a
-                                       di -= 2
                                }
                        } else {
                                for i := n - 1; i > 0; i-- {
                                        di := float64(i + i)
                                        a, b = b, b*di/x-a
-                                       di -= 2
                                        // scale b to avoid spurious overflow
                                        if b > 1e100 {
                                                a /= b
index ecec4b756c746f147c13aaced223f3f8c76f7311..5d2f489b70941ee4efb50e8ef34aa987c2ddba37 100644 (file)
@@ -16,9 +16,12 @@ func Modf(f float64) (int float64, frac float64) {
 
 func modf(f float64) (int float64, frac float64) {
        if f < 1 {
-               if f < 0 {
+               switch {
+               case f < 0:
                        int, frac = Modf(-f)
                        return -int, -frac
+               case f == 0:
+                       return f, f // Return -0, -0 when f == -0
                }
                return 0, f
        }
index 6360128e3916ad9195b0064961b6cfd384bb86ef..d693bfb52f243c5216ffbb1e384037675869a042 100644 (file)
@@ -113,19 +113,18 @@ func (r *Rand) Float64() float64 {
        //
        // 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
+       // that the result is always less than 1.0.
+       //
+       // We tried to fix this by mapping 1.0 back to 0.0, but since float64
+       // values near 0 are much denser than near 1, mapping 1 to 0 caused
+       // a theoretically significant overshoot in the probability of returning 0.
+       // Instead of that, if we round up to 1, just try again.
+       // Getting 1 only happens 1/2⁵³ of the time, so most clients
        // will not observe it anyway.
+again:
        f := float64(r.Int63()) / (1 << 63)
        if f == 1 {
-               f = 0
+               goto again // resample; this branch is taken O(never)
        }
        return f
 }
@@ -134,13 +133,11 @@ func (r *Rand) Float64() float64 {
 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).
+again:
        f := float32(r.Float64())
        if f == 1 {
-               f = 0
+               goto again // resample; this branch is taken O(very rarely)
        }
        return f
 }
@@ -148,6 +145,11 @@ func (r *Rand) Float32() float32 {
 // Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n).
 func (r *Rand) Perm(n int) []int {
        m := make([]int, n)
+       // In the following loop, the iteration when i=0 always swaps m[0] with m[0].
+       // A change to remove this useless iteration is to assign 1 to i in the init
+       // statement. But Perm also effects r. Making this change will affect
+       // the final state of r. So this change can't be made for compatibility
+       // reasons for Go 1.
        for i := 0; i < n; i++ {
                j := r.Intn(i + 1)
                m[i] = m[j]
@@ -156,6 +158,19 @@ func (r *Rand) Perm(n int) []int {
        return m
 }
 
+// Read generates len(p) random bytes and writes them into p. It
+// always returns len(p) and a nil error.
+func (r *Rand) Read(p []byte) (n int, err error) {
+       for i := 0; i < len(p); i += 7 {
+               val := r.src.Int63()
+               for j := 0; i+j < len(p) && j < 7; j++ {
+                       p[i+j] = byte(val)
+                       val >>= 8
+               }
+       }
+       return len(p), nil
+}
+
 /*
  * Top-level convenience functions
  */
@@ -209,6 +224,10 @@ func Float32() float32 { return globalRand.Float32() }
 // from the default Source.
 func Perm(n int) []int { return globalRand.Perm(n) }
 
+// Read generates len(p) random bytes from the default Source and
+// writes them into p. It always returns len(p) and a nil error.
+func Read(p []byte) (n int, err error) { return globalRand.Read(p) }
+
 // NormFloat64 returns a normally distributed float64 in the range
 // [-math.MaxFloat64, +math.MaxFloat64] with
 // standard normal distribution (mean = 0, stddev = 1)
index c61494f8eb8586cd9e517b4191cead5e704db7ba..8d68335fdd4686838e253b0201d828f1892cf617 100644 (file)
@@ -7,6 +7,7 @@ package rand
 import (
        "errors"
        "fmt"
+       "internal/testenv"
        "math"
        "os"
        "runtime"
@@ -327,9 +328,10 @@ func TestExpTables(t *testing.T) {
 func TestFloat32(t *testing.T) {
        // For issue 6721, the problem came after 7533753 calls, so check 10e6.
        num := int(10e6)
+       // But do the full amount only on builders (not locally).
        // But ARM5 floating point emulation is slow (Issue 10749), so
        // do less for that builder:
-       if testing.Short() && runtime.GOARCH == "arm" && os.Getenv("GOARM") == "5" {
+       if testing.Short() && (testenv.Builder() == "" || runtime.GOARCH == "arm" && os.Getenv("GOARM") == "5") {
                num /= 100 // 1.72 seconds instead of 172 seconds
        }
 
@@ -342,6 +344,59 @@ func TestFloat32(t *testing.T) {
        }
 }
 
+func testReadUniformity(t *testing.T, n int, seed int64) {
+       r := New(NewSource(seed))
+       buf := make([]byte, n)
+       nRead, err := r.Read(buf)
+       if err != nil {
+               t.Errorf("Read err %v", err)
+       }
+       if nRead != n {
+               t.Errorf("Read returned unexpected n; %d != %d", nRead, n)
+       }
+
+       // Expect a uniform distribution of byte values, which lie in [0, 255].
+       var (
+               mean       = 255.0 / 2
+               stddev     = math.Sqrt(255.0 * 255.0 / 12.0)
+               errorScale = stddev / math.Sqrt(float64(n))
+       )
+
+       expected := &statsResults{mean, stddev, 0.10 * errorScale, 0.08 * errorScale}
+
+       // Cast bytes as floats to use the common distribution-validity checks.
+       samples := make([]float64, n)
+       for i, val := range buf {
+               samples[i] = float64(val)
+       }
+       // Make sure that the entire set matches the expected distribution.
+       checkSampleDistribution(t, samples, expected)
+}
+
+func TestRead(t *testing.T) {
+       testBufferSizes := []int{
+               2, 4, 7, 64, 1024, 1 << 16, 1 << 20,
+       }
+       for _, seed := range testSeeds {
+               for _, n := range testBufferSizes {
+                       testReadUniformity(t, n, seed)
+               }
+       }
+}
+
+func TestReadEmpty(t *testing.T) {
+       r := New(NewSource(1))
+       buf := make([]byte, 0)
+       n, err := r.Read(buf)
+       if err != nil {
+               t.Errorf("Read err into empty buffer; %v", err)
+       }
+       if n != 0 {
+               t.Errorf("Read into empty buffer returned unexpected n of %d", n)
+       }
+
+}
+
 // Benchmarks
 
 func BenchmarkInt63Threadsafe(b *testing.B) {
@@ -405,3 +460,30 @@ func BenchmarkPerm30(b *testing.B) {
                r.Perm(30)
        }
 }
+
+func BenchmarkRead3(b *testing.B) {
+       r := New(NewSource(1))
+       buf := make([]byte, 3)
+       b.ResetTimer()
+       for n := b.N; n > 0; n-- {
+               r.Read(buf)
+       }
+}
+
+func BenchmarkRead64(b *testing.B) {
+       r := New(NewSource(1))
+       buf := make([]byte, 64)
+       b.ResetTimer()
+       for n := b.N; n > 0; n-- {
+               r.Read(buf)
+       }
+}
+
+func BenchmarkRead1000(b *testing.B) {
+       r := New(NewSource(1))
+       buf := make([]byte, 1000)
+       b.ResetTimer()
+       for n := b.N; n > 0; n-- {
+               r.Read(buf)
+       }
+}
index 2b012af893c7f1184088e9001e1591f5097e9fcf..9ae53574478a34f651a73d5f23bedb94669ac995 100644 (file)
@@ -25,6 +25,7 @@ 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}
+       var readBufferSizes = []int{1, 7, 8, 9, 10}
        r := New(NewSource(0))
 
        rv := reflect.ValueOf(r)
@@ -40,9 +41,6 @@ func TestRegress(t *testing.T) {
                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
@@ -74,14 +72,25 @@ func TestRegress(t *testing.T) {
 
                                case reflect.Int64:
                                        x = int64s[repeat%len(int64s)]
+
+                               case reflect.Slice:
+                                       if m.Name == "Read" {
+                                               n := readBufferSizes[repeat%len(readBufferSizes)]
+                                               x = make([]byte, n)
+                                       }
                                }
                                argstr = fmt.Sprint(x)
                                args = append(args, reflect.ValueOf(x))
                        }
-                       out := mv.Call(args)[0].Interface()
+
+                       var out interface{}
+                       out = mv.Call(args)[0].Interface()
                        if m.Name == "Int" || m.Name == "Intn" {
                                out = int64(out.(int))
                        }
+                       if m.Name == "Read" {
+                               out = args[0].Interface().([]byte)
+                       }
                        if *printgolden {
                                var val string
                                big := int64(1 << 60)
@@ -332,24 +341,44 @@ var regressGolden = []interface{}{
        []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()
+       []byte{0x1},                         // Read([0])
+       []byte{0xc0, 0x41, 0xd3, 0xff, 0x12, 0x4, 0x5b},                   // Read([0 0 0 0 0 0 0])
+       []byte{0x73, 0xc8, 0x6e, 0x4f, 0xf9, 0x5f, 0xf6, 0x62},            // Read([0 0 0 0 0 0 0 0])
+       []byte{0x4a, 0x2d, 0xb, 0x75, 0xfb, 0x18, 0xd, 0xaf, 0x48},        // Read([0 0 0 0 0 0 0 0 0])
+       []byte{0x39, 0x46, 0x51, 0x85, 0xf, 0xd4, 0xa1, 0x78, 0x89, 0x2e}, // Read([0 0 0 0 0 0 0 0 0 0])
+       []byte{0x51}, // Read([0])
+       []byte{0x4e, 0xe2, 0xd3, 0xd0, 0xd0, 0xde, 0x6b},                   // Read([0 0 0 0 0 0 0])
+       []byte{0xf8, 0xf9, 0xb4, 0x4c, 0xe8, 0x5f, 0xf0, 0x44},             // Read([0 0 0 0 0 0 0 0])
+       []byte{0x3b, 0xbf, 0x85, 0x7a, 0xab, 0x99, 0xc5, 0xb2, 0x52},       // Read([0 0 0 0 0 0 0 0 0])
+       []byte{0xa8, 0xae, 0xb7, 0x9e, 0xf8, 0x56, 0xf6, 0x59, 0xc1, 0x8f}, // Read([0 0 0 0 0 0 0 0 0 0])
+       []byte{0xc7}, // Read([0])
+       []byte{0x5f, 0x67, 0xcf, 0xe2, 0x42, 0xcf, 0x3c},                   // Read([0 0 0 0 0 0 0])
+       []byte{0xc3, 0x54, 0xf3, 0xed, 0xe2, 0xd6, 0xbe, 0xcc},             // Read([0 0 0 0 0 0 0 0])
+       []byte{0x6a, 0x9f, 0x4a, 0x57, 0x8b, 0xcb, 0x9e, 0xf2, 0xd4},       // Read([0 0 0 0 0 0 0 0 0])
+       []byte{0x6d, 0x29, 0x97, 0x61, 0xea, 0x9e, 0x4f, 0x5a, 0xa6, 0xae}, // Read([0 0 0 0 0 0 0 0 0 0])
+       []byte{0xaa}, // Read([0])
+       []byte{0x20, 0xef, 0xcd, 0x6c, 0xea, 0x84, 0xb6},                   // Read([0 0 0 0 0 0 0])
+       []byte{0x92, 0x5e, 0x60, 0x7b, 0xe0, 0x63, 0x71, 0x6f},             // Read([0 0 0 0 0 0 0 0])
+       []byte{0x4, 0x5c, 0x3f, 0x0, 0xf, 0x8a, 0x79, 0x6b, 0xce},          // Read([0 0 0 0 0 0 0 0 0])
+       []byte{0xaa, 0xca, 0xee, 0xdf, 0xad, 0x5b, 0x50, 0x66, 0x64, 0xe8}, // Read([0 0 0 0 0 0 0 0 0 0])
+       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()
 }
index 215d6485442971bf33adee6d81fff125f56e4a65..86c0452347819c2c97747524f4627232341a5d0f 100644 (file)
@@ -114,7 +114,7 @@ func sqrt(x float64) float64 {
        // normalize x
        exp := int((ix >> shift) & mask)
        if exp == 0 { // subnormal x
-               for ix&1<<shift == 0 {
+               for ix&(1<<shift) == 0 {
                        ix <<= 1
                        exp--
                }
index 9796f506dc28c31c98ad30e26f6c07f84c952b08..db4b5f4510ba495d3a27c44df89b94a79061406b 100644 (file)
@@ -54,35 +54,129 @@ func (e WordEncoder) encodeWord(charset, s string) string {
        buf := getBuffer()
        defer putBuffer(buf)
 
+       e.openWord(buf, charset)
+       if e == BEncoding {
+               e.bEncode(buf, charset, s)
+       } else {
+               e.qEncode(buf, charset, s)
+       }
+       closeWord(buf)
+
+       return buf.String()
+}
+
+const (
+       // The maximum length of an encoded-word is 75 characters.
+       // See RFC 2047, section 2.
+       maxEncodedWordLen = 75
+       // maxContentLen is how much content can be encoded, ignoring the header and
+       // 2-byte footer.
+       maxContentLen = maxEncodedWordLen - len("=?UTF-8?") - len("?=")
+)
+
+var maxBase64Len = base64.StdEncoding.DecodedLen(maxContentLen)
+
+// bEncode encodes s using base64 encoding and writes it to buf.
+func (e WordEncoder) bEncode(buf *bytes.Buffer, charset, s string) {
+       w := base64.NewEncoder(base64.StdEncoding, buf)
+       // If the charset is not UTF-8 or if the content is short, do not bother
+       // splitting the encoded-word.
+       if !isUTF8(charset) || base64.StdEncoding.EncodedLen(len(s)) <= maxContentLen {
+               io.WriteString(w, s)
+               w.Close()
+               return
+       }
+
+       var currentLen, last, runeLen int
+       for i := 0; i < len(s); i += runeLen {
+               // Multi-byte characters must not be split accross encoded-words.
+               // See RFC 2047, section 5.3.
+               _, runeLen = utf8.DecodeRuneInString(s[i:])
+
+               if currentLen+runeLen <= maxBase64Len {
+                       currentLen += runeLen
+               } else {
+                       io.WriteString(w, s[last:i])
+                       w.Close()
+                       e.splitWord(buf, charset)
+                       last = i
+                       currentLen = runeLen
+               }
+       }
+       io.WriteString(w, s[last:])
+       w.Close()
+}
+
+// qEncode encodes s using Q encoding and writes it to buf. It splits the
+// encoded-words when necessary.
+func (e WordEncoder) qEncode(buf *bytes.Buffer, charset, s string) {
+       // We only split encoded-words when the charset is UTF-8.
+       if !isUTF8(charset) {
+               writeQString(buf, s)
+               return
+       }
+
+       var currentLen, runeLen int
+       for i := 0; i < len(s); i += runeLen {
+               b := s[i]
+               // Multi-byte characters must not be split accross encoded-words.
+               // See RFC 2047, section 5.3.
+               var encLen int
+               if b >= ' ' && b <= '~' && b != '=' && b != '?' && b != '_' {
+                       runeLen, encLen = 1, 1
+               } else {
+                       _, runeLen = utf8.DecodeRuneInString(s[i:])
+                       encLen = 3 * runeLen
+               }
+
+               if currentLen+encLen > maxContentLen {
+                       e.splitWord(buf, charset)
+                       currentLen = 0
+               }
+               writeQString(buf, s[i:i+runeLen])
+               currentLen += encLen
+       }
+}
+
+// writeQString encodes s using Q encoding and writes it to buf.
+func writeQString(buf *bytes.Buffer, s string) {
+       for i := 0; i < len(s); i++ {
+               switch b := s[i]; {
+               case b == ' ':
+                       buf.WriteByte('_')
+               case b >= '!' && b <= '~' && b != '=' && b != '?' && b != '_':
+                       buf.WriteByte(b)
+               default:
+                       buf.WriteByte('=')
+                       buf.WriteByte(upperhex[b>>4])
+                       buf.WriteByte(upperhex[b&0x0f])
+               }
+       }
+}
+
+// openWord writes the beginning of an encoded-word into buf.
+func (e WordEncoder) openWord(buf *bytes.Buffer, charset string) {
        buf.WriteString("=?")
        buf.WriteString(charset)
        buf.WriteByte('?')
        buf.WriteByte(byte(e))
        buf.WriteByte('?')
+}
 
-       if e == BEncoding {
-               w := base64.NewEncoder(base64.StdEncoding, buf)
-               io.WriteString(w, s)
-               w.Close()
-       } else {
-               enc := make([]byte, 3)
-               for i := 0; i < len(s); i++ {
-                       b := s[i]
-                       switch {
-                       case b == ' ':
-                               buf.WriteByte('_')
-                       case b <= '~' && b >= '!' && b != '=' && b != '?' && b != '_':
-                               buf.WriteByte(b)
-                       default:
-                               enc[0] = '='
-                               enc[1] = upperhex[b>>4]
-                               enc[2] = upperhex[b&0x0f]
-                               buf.Write(enc)
-                       }
-               }
-       }
+// closeWord writes the end of an encoded-word into buf.
+func closeWord(buf *bytes.Buffer) {
        buf.WriteString("?=")
-       return buf.String()
+}
+
+// splitWord closes the current encoded-word and opens a new one.
+func (e WordEncoder) splitWord(buf *bytes.Buffer, charset string) {
+       closeWord(buf)
+       buf.WriteByte(' ')
+       e.openWord(buf, charset)
+}
+
+func isUTF8(charset string) bool {
+       return strings.EqualFold(charset, "UTF-8")
 }
 
 const upperhex = "0123456789ABCDEF"
@@ -98,15 +192,26 @@ type WordDecoder struct {
        CharsetReader func(charset string, input io.Reader) (io.Reader, error)
 }
 
-// Decode decodes an encoded-word. If word is not a valid RFC 2047 encoded-word,
-// word is returned unchanged.
+// Decode decodes an RFC 2047 encoded-word.
 func (d *WordDecoder) Decode(word string) (string, error) {
-       fields := strings.Split(word, "?") // TODO: remove allocation?
-       if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" || len(fields[2]) != 1 {
+       if !strings.HasPrefix(word, "=?") || !strings.HasSuffix(word, "?=") || strings.Count(word, "?") != 4 {
+               return "", errInvalidWord
+       }
+       word = word[2 : len(word)-2]
+
+       // split delimits the first 2 fields
+       split := strings.IndexByte(word, '?')
+       // the field after split must only be one byte
+       if word[split+2] != '?' {
                return "", errInvalidWord
        }
 
-       content, err := decode(fields[2][0], fields[3])
+       // split word "UTF-8?q?ascii" into "UTF-8", 'q', and "ascii"
+       charset := word[:split]
+       encoding := word[split+1]
+       text := word[split+3:]
+
+       content, err := decode(encoding, text)
        if err != nil {
                return "", err
        }
@@ -114,7 +219,7 @@ func (d *WordDecoder) Decode(word string) (string, error) {
        buf := getBuffer()
        defer putBuffer(buf)
 
-       if err := d.convert(buf, fields[1], content); err != nil {
+       if err := d.convert(buf, charset, content); err != nil {
                return "", err
        }
 
index 2beff5d3414a7ba8c678c5328f3992a1ed417960..5fcd7a06dd6a0229e65fca7d101dca6f36f2921d 100644 (file)
 package mime
 
 import (
-       "bytes"
        "errors"
-       "fmt"
        "io"
        "io/ioutil"
        "strings"
        "testing"
 )
 
-func ExampleWordEncoder_Encode() {
-       fmt.Println(QEncoding.Encode("utf-8", "¡Hola, señor!"))
-       fmt.Println(QEncoding.Encode("utf-8", "Hello!"))
-       fmt.Println(BEncoding.Encode("UTF-8", "¡Hola, señor!"))
-       fmt.Println(QEncoding.Encode("ISO-8859-1", "Caf\xE9"))
-       // Output:
-       // =?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=
-       // Hello!
-       // =?UTF-8?b?wqFIb2xhLCBzZcOxb3Ih?=
-       // =?ISO-8859-1?q?Caf=E9?=
-}
-
-func ExampleWordDecoder_Decode() {
-       dec := new(WordDecoder)
-       header, err := dec.Decode("=?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=")
-       if err != nil {
-               panic(err)
-       }
-       fmt.Println(header)
-
-       dec.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) {
-               switch charset {
-               case "x-case":
-                       // Fake character set for example.
-                       // Real use would integrate with packages such
-                       // as code.google.com/p/go-charset
-                       content, err := ioutil.ReadAll(input)
-                       if err != nil {
-                               return nil, err
-                       }
-                       return bytes.NewReader(bytes.ToUpper(content)), nil
-               default:
-                       return nil, fmt.Errorf("unhandled charset %q", charset)
-               }
-       }
-       header, err = dec.Decode("=?x-case?q?hello!?=")
-       if err != nil {
-               panic(err)
-       }
-       fmt.Println(header)
-       // Output:
-       // ¡Hola, señor!
-       // HELLO!
-}
-
-func ExampleWordDecoder_DecodeHeader() {
-       dec := new(WordDecoder)
-       header, err := dec.DecodeHeader("=?utf-8?q?=C3=89ric?= <eric@example.org>, =?utf-8?q?Ana=C3=AFs?= <anais@example.org>")
-       if err != nil {
-               panic(err)
-       }
-       fmt.Println(header)
-
-       header, err = dec.DecodeHeader("=?utf-8?q?=C2=A1Hola,?= =?utf-8?q?_se=C3=B1or!?=")
-       if err != nil {
-               panic(err)
-       }
-       fmt.Println(header)
-
-       dec.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) {
-               switch charset {
-               case "x-case":
-                       // Fake character set for example.
-                       // Real use would integrate with packages such
-                       // as code.google.com/p/go-charset
-                       content, err := ioutil.ReadAll(input)
-                       if err != nil {
-                               return nil, err
-                       }
-                       return bytes.NewReader(bytes.ToUpper(content)), nil
-               default:
-                       return nil, fmt.Errorf("unhandled charset %q", charset)
-               }
-       }
-       header, err = dec.DecodeHeader("=?x-case?q?hello_?= =?x-case?q?world!?=")
-       if err != nil {
-               panic(err)
-       }
-       fmt.Println(header)
-       // Output:
-       // Éric <eric@example.org>, Anaïs <anais@example.org>
-       // ¡Hola, señor!
-       // HELLO WORLD!
-}
-
 func TestEncodeWord(t *testing.T) {
        utf8, iso88591 := "utf-8", "iso-8859-1"
        tests := []struct {
@@ -114,6 +27,14 @@ func TestEncodeWord(t *testing.T) {
                {QEncoding, iso88591, "a", "a"},
                {QEncoding, utf8, "123 456", "123 456"},
                {QEncoding, utf8, "\t !\"#$%&'()*+,-./ :;<>?@[\\]^_`{|}~", "\t !\"#$%&'()*+,-./ :;<>?@[\\]^_`{|}~"},
+               {QEncoding, utf8, strings.Repeat("é", 10), "=?utf-8?q?" + strings.Repeat("=C3=A9", 10) + "?="},
+               {QEncoding, utf8, strings.Repeat("é", 11), "=?utf-8?q?" + strings.Repeat("=C3=A9", 10) + "?= =?utf-8?q?=C3=A9?="},
+               {QEncoding, iso88591, strings.Repeat("\xe9", 22), "=?iso-8859-1?q?" + strings.Repeat("=E9", 22) + "?="},
+               {QEncoding, utf8, strings.Repeat("\x80", 22), "=?utf-8?q?" + strings.Repeat("=80", 21) + "?= =?utf-8?q?=80?="},
+               {BEncoding, utf8, strings.Repeat("é", 24), "=?utf-8?b?" + strings.Repeat("w6nDqcOp", 8) + "?="},
+               {BEncoding, utf8, strings.Repeat("é", 27), "=?utf-8?b?" + strings.Repeat("w6nDqcOp", 8) + "?= =?utf-8?b?w6nDqcOp?="},
+               {BEncoding, iso88591, strings.Repeat("\xe9", 45), "=?iso-8859-1?b?" + strings.Repeat("6enp", 15) + "?="},
+               {BEncoding, utf8, strings.Repeat("\x80", 51), "=?utf-8?b?" + strings.Repeat("gICA", 16) + "?= =?utf-8?b?gICA?="},
        }
 
        for _, test := range tests {
diff --git a/libgo/go/mime/example_test.go b/libgo/go/mime/example_test.go
new file mode 100644 (file)
index 0000000..12aafdc
--- /dev/null
@@ -0,0 +1,100 @@
+// Copyright 2015 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 ignore
+
+package mime_test
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "io/ioutil"
+       "mime"
+)
+
+func ExampleWordEncoder_Encode() {
+       fmt.Println(mime.QEncoding.Encode("utf-8", "¡Hola, señor!"))
+       fmt.Println(mime.QEncoding.Encode("utf-8", "Hello!"))
+       fmt.Println(mime.BEncoding.Encode("UTF-8", "¡Hola, señor!"))
+       fmt.Println(mime.QEncoding.Encode("ISO-8859-1", "Caf\xE9"))
+       // Output:
+       // =?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=
+       // Hello!
+       // =?UTF-8?b?wqFIb2xhLCBzZcOxb3Ih?=
+       // =?ISO-8859-1?q?Caf=E9?=
+}
+
+func ExampleWordDecoder_Decode() {
+       dec := new(mime.WordDecoder)
+       header, err := dec.Decode("=?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=")
+       if err != nil {
+               panic(err)
+       }
+       fmt.Println(header)
+
+       dec.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) {
+               switch charset {
+               case "x-case":
+                       // Fake character set for example.
+                       // Real use would integrate with packages such
+                       // as code.google.com/p/go-charset
+                       content, err := ioutil.ReadAll(input)
+                       if err != nil {
+                               return nil, err
+                       }
+                       return bytes.NewReader(bytes.ToUpper(content)), nil
+               default:
+                       return nil, fmt.Errorf("unhandled charset %q", charset)
+               }
+       }
+       header, err = dec.Decode("=?x-case?q?hello!?=")
+       if err != nil {
+               panic(err)
+       }
+       fmt.Println(header)
+       // Output:
+       // ¡Hola, señor!
+       // HELLO!
+}
+
+func ExampleWordDecoder_DecodeHeader() {
+       dec := new(mime.WordDecoder)
+       header, err := dec.DecodeHeader("=?utf-8?q?=C3=89ric?= <eric@example.org>, =?utf-8?q?Ana=C3=AFs?= <anais@example.org>")
+       if err != nil {
+               panic(err)
+       }
+       fmt.Println(header)
+
+       header, err = dec.DecodeHeader("=?utf-8?q?=C2=A1Hola,?= =?utf-8?q?_se=C3=B1or!?=")
+       if err != nil {
+               panic(err)
+       }
+       fmt.Println(header)
+
+       dec.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) {
+               switch charset {
+               case "x-case":
+                       // Fake character set for example.
+                       // Real use would integrate with packages such
+                       // as code.google.com/p/go-charset
+                       content, err := ioutil.ReadAll(input)
+                       if err != nil {
+                               return nil, err
+                       }
+                       return bytes.NewReader(bytes.ToUpper(content)), nil
+               default:
+                       return nil, fmt.Errorf("unhandled charset %q", charset)
+               }
+       }
+       header, err = dec.DecodeHeader("=?x-case?q?hello_?= =?x-case?q?world!?=")
+       if err != nil {
+               panic(err)
+       }
+       fmt.Println(header)
+       // Output:
+       // Éric <eric@example.org>, Anaïs <anais@example.org>
+       // ¡Hola, señor!
+       // HELLO WORLD!
+}
index ad63f9bb98e9a4197070f99b82d512b9f3812eb0..efee65bb00b30e1cd05026ae0af07b818adb6853 100644 (file)
@@ -19,18 +19,21 @@ import (
 // When any of the arguments result in a standard violation then
 // FormatMediaType returns the empty string.
 func FormatMediaType(t string, param map[string]string) string {
-       slash := strings.Index(t, "/")
-       if slash == -1 {
-               return ""
-       }
-       major, sub := t[:slash], t[slash+1:]
-       if !isToken(major) || !isToken(sub) {
-               return ""
-       }
        var b bytes.Buffer
-       b.WriteString(strings.ToLower(major))
-       b.WriteByte('/')
-       b.WriteString(strings.ToLower(sub))
+       if slash := strings.Index(t, "/"); slash == -1 {
+               if !isToken(t) {
+                       return ""
+               }
+               b.WriteString(strings.ToLower(t))
+       } else {
+               major, sub := t[:slash], t[slash+1:]
+               if !isToken(major) || !isToken(sub) {
+                       return ""
+               }
+               b.WriteString(strings.ToLower(major))
+               b.WriteByte('/')
+               b.WriteString(strings.ToLower(sub))
+       }
 
        attrs := make([]string, 0, len(param))
        for a := range param {
@@ -237,24 +240,23 @@ func consumeToken(v string) (token, rest string) {
 // quoted-string) and the rest of the string.  On failure, returns
 // ("", v).
 func consumeValue(v string) (value, rest string) {
-       if !strings.HasPrefix(v, `"`) && !strings.HasPrefix(v, `'`) {
+       if v == "" {
+               return
+       }
+       if v[0] != '"' {
                return consumeToken(v)
        }
 
-       leadQuote := rune(v[0])
-
        // parse a quoted-string
        rest = v[1:] // consume the leading quote
        buffer := new(bytes.Buffer)
-       var idx int
-       var r rune
        var nextIsLiteral bool
-       for idx, r = range rest {
+       for idx, r := range rest {
                switch {
                case nextIsLiteral:
                        buffer.WriteRune(r)
                        nextIsLiteral = false
-               case r == leadQuote:
+               case r == '"':
                        return buffer.String(), rest[idx+1:]
                case r == '\\':
                        nextIsLiteral = true
@@ -287,10 +289,11 @@ func consumeMediaParam(v string) (param, value, rest string) {
        }
        rest = rest[1:] // consume equals sign
        rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
-       value, rest = consumeValue(rest)
-       if value == "" {
+       value, rest2 := consumeValue(rest)
+       if value == "" && rest2 == rest {
                return "", "", v
        }
+       rest = rest2
        return param, value, rest
 }
 
index 026bfa4d73468117aeca38445aedaf31122b960d..9afa55825fee8f9ce56e544274eb71d053bd03fe 100644 (file)
@@ -159,7 +159,7 @@ func TestParseMediaType(t *testing.T) {
                        m("filename", "foo.html")},
                {`attachment; filename='foo.html'`,
                        "attachment",
-                       m("filename", "foo.html")},
+                       m("filename", "'foo.html'")},
                {`attachment; filename="foo-%41.html"`,
                        "attachment",
                        m("filename", "foo-%41.html")},
@@ -217,6 +217,9 @@ func TestParseMediaType(t *testing.T) {
                {`form-data; firstname="Брэд"; lastname="Фицпатрик"`,
                        "form-data",
                        m("firstname", "Брэд", "lastname", "Фицпатрик")},
+
+               // Empty string used to be mishandled.
+               {`foo; bar=""`, "foo", m("bar", "")},
        }
        for _, test := range tests {
                mt, params, err := ParseMediaType(test.in)
@@ -281,7 +284,7 @@ type formatTest struct {
 }
 
 var formatTests = []formatTest{
-       {"noslash", nil, ""},
+       {"noslash", map[string]string{"X": "Y"}, "noslash; x=Y"}, // e.g. Content-Disposition values (RFC 2183); issue 11289
        {"foo bar/baz", nil, ""},
        {"foo/bar baz", nil, ""},
        {"foo/BAR", nil, "foo/bar"},
@@ -294,6 +297,8 @@ var formatTests = []formatTest{
        {"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"},
+       {"foo/bar", map[string]string{"0": "'", "9": "'"}, "foo/bar; 0='; 9='"},
+       {"foo", map[string]string{"bar": ""}, `foo; bar=""`},
 }
 
 func TestFormatMediaType(t *testing.T) {
index 6f65a55de276bd9bc02a32e51de535bfc2a70577..3b746a5e15756c5281b212017f54775cdf20cfd8 100644 (file)
@@ -25,6 +25,11 @@ import (
 
 var emptyParams = make(map[string]string)
 
+// This constant needs to be at least 76 for this package to work correctly.
+// This is because \r\n--separator_of_len_70- would fill the buffer and it
+// wouldn't be safe to consume a single byte from it.
+const peekBufferSize = 4096
+
 // A Part represents a single part in a multipart body.
 type Part struct {
        // The headers of the body, if any, with the keys canonicalized
@@ -91,7 +96,7 @@ func (p *Part) parseContentDisposition() {
 func NewReader(r io.Reader, boundary string) *Reader {
        b := []byte("\r\n--" + boundary + "--")
        return &Reader{
-               bufReader:        bufio.NewReader(r),
+               bufReader:        bufio.NewReaderSize(r, peekBufferSize),
                nl:               b[:2],
                nlDashBoundary:   b[:len(b)-2],
                dashBoundaryDash: b[2:],
@@ -148,7 +153,7 @@ func (pr partReader) Read(d []byte) (n int, err error) {
                // the read request.  No need to parse more at the moment.
                return p.buffer.Read(d)
        }
-       peek, err := p.mr.bufReader.Peek(4096) // TODO(bradfitz): add buffer size accessor
+       peek, err := p.mr.bufReader.Peek(peekBufferSize) // TODO(bradfitz): add buffer size accessor
 
        // Look for an immediate empty part without a leading \r\n
        // before the boundary separator.  Some MIME code makes empty
@@ -229,6 +234,7 @@ func (r *Reader) NextPart() (*Part, error) {
        expectNewPart := false
        for {
                line, err := r.bufReader.ReadSlice('\n')
+
                if err == io.EOF && r.isFinalBoundary(line) {
                        // If the buffer ends in "--boundary--" without the
                        // trailing "\r\n", ReadSlice will return an error
@@ -343,20 +349,24 @@ func (mr *Reader) peekBufferIsEmptyPart(peek []byte) bool {
 // peekBufferSeparatorIndex returns the index of mr.nlDashBoundary in
 // peek and whether it is a real boundary (and not a prefix of an
 // unrelated separator). To be the end, the peek buffer must contain a
-// newline after the boundary.
+// newline after the boundary or contain the ending boundary (--separator--).
 func (mr *Reader) peekBufferSeparatorIndex(peek []byte) (idx int, isEnd bool) {
        idx = bytes.Index(peek, mr.nlDashBoundary)
        if idx == -1 {
                return
        }
+
        peek = peek[idx+len(mr.nlDashBoundary):]
+       if len(peek) == 0 || len(peek) == 1 && peek[0] == '-' {
+               return idx, false
+       }
        if len(peek) > 1 && peek[0] == '-' && peek[1] == '-' {
                return idx, true
        }
        peek = skipLWSPChar(peek)
        // Don't have a complete line after the peek.
        if bytes.IndexByte(peek, '\n') == -1 {
-               return -1, false
+               return idx, false
        }
        if len(peek) > 0 && peek[0] == '\n' {
                return idx, true
index 30452d1d458cd76885935d26866b132249461097..d06bb4159aaf0de2148ab3f7102da9aa93828705 100644 (file)
@@ -616,6 +616,86 @@ html things
                        },
                },
        },
+       // Issue 12662: Check that we don't consume the leading \r if the peekBuffer
+       // ends in '\r\n--separator-'
+       {
+               name: "peek buffer boundary condition",
+               sep:  "00ffded004d4dd0fdf945fbdef9d9050cfd6a13a821846299b27fc71b9db",
+               in: strings.Replace(`--00ffded004d4dd0fdf945fbdef9d9050cfd6a13a821846299b27fc71b9db
+Content-Disposition: form-data; name="block"; filename="block"
+Content-Type: application/octet-stream
+
+`+strings.Repeat("A", peekBufferSize-65)+"\n--00ffded004d4dd0fdf945fbdef9d9050cfd6a13a821846299b27fc71b9db--", "\n", "\r\n", -1),
+               want: []headerBody{
+                       {textproto.MIMEHeader{"Content-Type": {`application/octet-stream`}, "Content-Disposition": {`form-data; name="block"; filename="block"`}},
+                               strings.Repeat("A", peekBufferSize-65),
+                       },
+               },
+       },
+       // Issue 12662: Same test as above with \r\n at the end
+       {
+               name: "peek buffer boundary condition",
+               sep:  "00ffded004d4dd0fdf945fbdef9d9050cfd6a13a821846299b27fc71b9db",
+               in: strings.Replace(`--00ffded004d4dd0fdf945fbdef9d9050cfd6a13a821846299b27fc71b9db
+Content-Disposition: form-data; name="block"; filename="block"
+Content-Type: application/octet-stream
+
+`+strings.Repeat("A", peekBufferSize-65)+"\n--00ffded004d4dd0fdf945fbdef9d9050cfd6a13a821846299b27fc71b9db--\n", "\n", "\r\n", -1),
+               want: []headerBody{
+                       {textproto.MIMEHeader{"Content-Type": {`application/octet-stream`}, "Content-Disposition": {`form-data; name="block"; filename="block"`}},
+                               strings.Repeat("A", peekBufferSize-65),
+                       },
+               },
+       },
+       // Issue 12662v2: We want to make sure that for short buffers that end with
+       // '\r\n--separator-' we always consume at least one (valid) symbol from the
+       // peekBuffer
+       {
+               name: "peek buffer boundary condition",
+               sep:  "aaaaaaaaaa00ffded004d4dd0fdf945fbdef9d9050cfd6a13a821846299b27fc71b9db",
+               in: strings.Replace(`--aaaaaaaaaa00ffded004d4dd0fdf945fbdef9d9050cfd6a13a821846299b27fc71b9db
+Content-Disposition: form-data; name="block"; filename="block"
+Content-Type: application/octet-stream
+
+`+strings.Repeat("A", peekBufferSize)+"\n--aaaaaaaaaa00ffded004d4dd0fdf945fbdef9d9050cfd6a13a821846299b27fc71b9db--", "\n", "\r\n", -1),
+               want: []headerBody{
+                       {textproto.MIMEHeader{"Content-Type": {`application/octet-stream`}, "Content-Disposition": {`form-data; name="block"; filename="block"`}},
+                               strings.Repeat("A", peekBufferSize),
+                       },
+               },
+       },
+       // Context: https://github.com/camlistore/camlistore/issues/642
+       // If the file contents in the form happens to have a size such as:
+       // size = peekBufferSize - (len("\n--") + len(boundary) + len("\r") + 1), (modulo peekBufferSize)
+       // then peekBufferSeparatorIndex was wrongly returning (-1, false), which was leading to an nCopy
+       // cut such as:
+       // "somedata\r| |\n--Boundary\r" (instead of "somedata| |\r\n--Boundary\r"), which was making the
+       // subsequent Read miss the boundary.
+       {
+               name: "safeCount off by one",
+               sep:  "08b84578eabc563dcba967a945cdf0d9f613864a8f4a716f0e81caa71a74",
+               in: strings.Replace(`--08b84578eabc563dcba967a945cdf0d9f613864a8f4a716f0e81caa71a74
+Content-Disposition: form-data; name="myfile"; filename="my-file.txt"
+Content-Type: application/octet-stream
+
+`, "\n", "\r\n", -1) +
+                       strings.Repeat("A", peekBufferSize-(len("\n--")+len("08b84578eabc563dcba967a945cdf0d9f613864a8f4a716f0e81caa71a74")+len("\r")+1)) +
+                       strings.Replace(`
+--08b84578eabc563dcba967a945cdf0d9f613864a8f4a716f0e81caa71a74
+Content-Disposition: form-data; name="key"
+
+val
+--08b84578eabc563dcba967a945cdf0d9f613864a8f4a716f0e81caa71a74--
+`, "\n", "\r\n", -1),
+               want: []headerBody{
+                       {textproto.MIMEHeader{"Content-Type": {`application/octet-stream`}, "Content-Disposition": {`form-data; name="myfile"; filename="my-file.txt"`}},
+                               strings.Repeat("A", peekBufferSize-(len("\n--")+len("08b84578eabc563dcba967a945cdf0d9f613864a8f4a716f0e81caa71a74")+len("\r")+1)),
+                       },
+                       {textproto.MIMEHeader{"Content-Disposition": {`form-data; name="key"`}},
+                               "val",
+                       },
+               },
+       },
 
        roundTripParseTest(),
 }
@@ -656,6 +736,53 @@ Cases:
        }
 }
 
+func partsFromReader(r *Reader) ([]headerBody, error) {
+       got := []headerBody{}
+       for {
+               p, err := r.NextPart()
+               if err == io.EOF {
+                       return got, nil
+               }
+               if err != nil {
+                       return nil, fmt.Errorf("NextPart: %v", err)
+               }
+               pbody, err := ioutil.ReadAll(p)
+               if err != nil {
+                       return nil, fmt.Errorf("error reading part: %v", err)
+               }
+               got = append(got, headerBody{p.Header, string(pbody)})
+       }
+}
+
+func TestParseAllSizes(t *testing.T) {
+       const maxSize = 5 << 10
+       var buf bytes.Buffer
+       body := strings.Repeat("a", maxSize)
+       bodyb := []byte(body)
+       for size := 0; size < maxSize; size++ {
+               buf.Reset()
+               w := NewWriter(&buf)
+               part, _ := w.CreateFormField("f")
+               part.Write(bodyb[:size])
+               part, _ = w.CreateFormField("key")
+               part.Write([]byte("val"))
+               w.Close()
+               r := NewReader(&buf, w.Boundary())
+               got, err := partsFromReader(r)
+               if err != nil {
+                       t.Errorf("For size %d: %v", size, err)
+                       continue
+               }
+               if len(got) != 2 {
+                       t.Errorf("For size %d, num parts = %d; want 2", size, len(got))
+                       continue
+               }
+               if got[0].body != body[:size] {
+                       t.Errorf("For size %d, got unexpected len %d: %q", size, len(got[0].body), got[0].body)
+               }
+       }
+}
+
 func roundTripParseTest() parseTest {
        t := parseTest{
                name: "round trip",
index e22fbac5cee1a99ac0ae7fa7ff31e6e4036a15a0..58ab7d706c61be3db190b14f21277e79437ba23a 100644 (file)
@@ -197,6 +197,24 @@ func (s *byRFC6724) Less(i, j int) bool {
        if da4 == db4 {
                commonA := commonPrefixLen(SourceDA, DA)
                commonB := commonPrefixLen(SourceDB, DB)
+
+               // CommonPrefixLen doesn't really make sense for IPv4, and even
+               // causes problems for common load balancing practices
+               // (e.g., https://golang.org/issue/13283).  Glibc instead only
+               // uses CommonPrefixLen for IPv4 when the source and destination
+               // addresses are on the same subnet, but that requires extra
+               // work to find the netmask for our source addresses.  As a
+               // simpler heuristic, we limit its use to when the source and
+               // destination belong to the same special purpose block.
+               if da4 {
+                       if !sameIPv4SpecialPurposeBlock(SourceDA, DA) {
+                               commonA = 0
+                       }
+                       if !sameIPv4SpecialPurposeBlock(SourceDB, DB) {
+                               commonB = 0
+                       }
+               }
+
                if commonA > commonB {
                        return preferDA
                }
@@ -386,3 +404,28 @@ func commonPrefixLen(a, b IP) (cpl int) {
        }
        return
 }
+
+// sameIPv4SpecialPurposeBlock reports whether a and b belong to the same
+// address block reserved by the IANA IPv4 Special-Purpose Address Registry:
+// http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
+func sameIPv4SpecialPurposeBlock(a, b IP) bool {
+       a, b = a.To4(), b.To4()
+       if a == nil || b == nil || a[0] != b[0] {
+               return false
+       }
+       // IANA defines more special-purpose blocks, but these are the only
+       // ones likely to be relevant to typical Go systems.
+       switch a[0] {
+       case 10: // 10.0.0.0/8: Private-Use
+               return true
+       case 127: // 127.0.0.0/8: Loopback
+               return true
+       case 169: // 169.254.0.0/16: Link Local
+               return a[1] == 254 && b[1] == 254
+       case 172: // 172.16.0.0/12: Private-Use
+               return a[1]&0xf0 == 16 && b[1]&0xf0 == 16
+       case 192: // 192.168.0.0/16: Private-Use
+               return a[1] == 168 && b[1] == 168
+       }
+       return false
+}
index 562022772fa853c0e543d07b2502c91a117f5f1a..80aa4eb195b535ffb1811b2c60660221def9429c 100644 (file)
@@ -87,6 +87,57 @@ func TestSortByRFC6724(t *testing.T) {
                        },
                        reverse: true,
                },
+
+               // Issue 13283.  Having a 10/8 source address does not
+               // mean we should prefer 23/8 destination addresses.
+               {
+                       in: []IPAddr{
+                               {IP: ParseIP("54.83.193.112")},
+                               {IP: ParseIP("184.72.238.214")},
+                               {IP: ParseIP("23.23.172.185")},
+                               {IP: ParseIP("75.101.148.21")},
+                               {IP: ParseIP("23.23.134.56")},
+                               {IP: ParseIP("23.21.50.150")},
+                       },
+                       srcs: []IP{
+                               ParseIP("10.2.3.4"),
+                               ParseIP("10.2.3.4"),
+                               ParseIP("10.2.3.4"),
+                               ParseIP("10.2.3.4"),
+                               ParseIP("10.2.3.4"),
+                               ParseIP("10.2.3.4"),
+                       },
+                       want: []IPAddr{
+                               {IP: ParseIP("54.83.193.112")},
+                               {IP: ParseIP("184.72.238.214")},
+                               {IP: ParseIP("23.23.172.185")},
+                               {IP: ParseIP("75.101.148.21")},
+                               {IP: ParseIP("23.23.134.56")},
+                               {IP: ParseIP("23.21.50.150")},
+                       },
+                       reverse: false,
+               },
+
+               // Prefer longer common prefixes, but only for IPv4 address
+               // pairs in the same special-purpose block.
+               {
+                       in: []IPAddr{
+                               {IP: ParseIP("1.2.3.4")},
+                               {IP: ParseIP("10.55.0.1")},
+                               {IP: ParseIP("10.66.0.1")},
+                       },
+                       srcs: []IP{
+                               ParseIP("1.2.3.5"),
+                               ParseIP("10.66.1.2"),
+                               ParseIP("10.66.1.2"),
+                       },
+                       want: []IPAddr{
+                               {IP: ParseIP("10.66.0.1")},
+                               {IP: ParseIP("10.55.0.1")},
+                               {IP: ParseIP("1.2.3.4")},
+                       },
+                       reverse: true,
+               },
        }
        for i, tt := range tests {
                inCopy := make([]IPAddr, len(tt.in))
@@ -217,3 +268,67 @@ func TestRFC6724CommonPrefixLength(t *testing.T) {
        }
 
 }
+
+func mustParseCIDRs(t *testing.T, blocks ...string) []*IPNet {
+       res := make([]*IPNet, len(blocks))
+       for i, block := range blocks {
+               var err error
+               _, res[i], err = ParseCIDR(block)
+               if err != nil {
+                       t.Fatalf("ParseCIDR(%s) failed: %v", block, err)
+               }
+       }
+       return res
+}
+
+func TestSameIPv4SpecialPurposeBlock(t *testing.T) {
+       blocks := mustParseCIDRs(t,
+               "10.0.0.0/8",
+               "127.0.0.0/8",
+               "169.254.0.0/16",
+               "172.16.0.0/12",
+               "192.168.0.0/16",
+       )
+
+       addrs := []struct {
+               ip    IP
+               block int // index or -1
+       }{
+               {IP{1, 2, 3, 4}, -1},
+               {IP{2, 3, 4, 5}, -1},
+               {IP{10, 2, 3, 4}, 0},
+               {IP{10, 6, 7, 8}, 0},
+               {IP{127, 0, 0, 1}, 1},
+               {IP{127, 255, 255, 255}, 1},
+               {IP{169, 254, 77, 99}, 2},
+               {IP{169, 254, 44, 22}, 2},
+               {IP{169, 255, 0, 1}, -1},
+               {IP{172, 15, 5, 6}, -1},
+               {IP{172, 16, 32, 41}, 3},
+               {IP{172, 31, 128, 9}, 3},
+               {IP{172, 32, 88, 100}, -1},
+               {IP{192, 168, 1, 1}, 4},
+               {IP{192, 168, 128, 42}, 4},
+               {IP{192, 169, 1, 1}, -1},
+       }
+
+       for i, addr := range addrs {
+               for j, block := range blocks {
+                       got := block.Contains(addr.ip)
+                       want := addr.block == j
+                       if got != want {
+                               t.Errorf("%d/%d. %s.Contains(%s): got %v, want %v", i, j, block, addr.ip, got, want)
+                       }
+               }
+       }
+
+       for i, addr1 := range addrs {
+               for j, addr2 := range addrs {
+                       got := sameIPv4SpecialPurposeBlock(addr1.ip, addr2.ip)
+                       want := addr1.block >= 0 && addr1.block == addr2.block
+                       if got != want {
+                               t.Errorf("%d/%d. sameIPv4SpecialPurposeBlock(%s, %s): got %v, want %v", i, j, addr1.ip, addr2.ip, got, want)
+                       }
+               }
+       }
+}
index 81816c644f80ed8aa5cfdbbd4c5a8c8effdeeb82..9dcd15883e4d55da40e80aa93068105d17cce4eb 100644 (file)
@@ -25,8 +25,8 @@ func cgoSockaddrInet4(ip IP) *syscall.RawSockaddr {
        return (*syscall.RawSockaddr)(unsafe.Pointer(&sa))
 }
 
-func cgoSockaddrInet6(ip IP) *syscall.RawSockaddr {
-       sa := syscall.RawSockaddrInet6{Family: syscall.AF_INET6}
+func cgoSockaddrInet6(ip IP, zone int) *syscall.RawSockaddr {
+       sa := syscall.RawSockaddrInet6{Family: syscall.AF_INET6, Scope_id: uint32(zone)}
        copy(sa.Addr[:], ip)
        return (*syscall.RawSockaddr)(unsafe.Pointer(&sa))
 }
index e80e03b2b1ebe6035dab76dcfad4ec424aaddc53..432634b55215835744d674a0e99ac953afdc0928 100644 (file)
@@ -25,8 +25,8 @@ func cgoSockaddrInet4(ip IP) *syscall.RawSockaddr {
        return (*syscall.RawSockaddr)(unsafe.Pointer(&sa))
 }
 
-func cgoSockaddrInet6(ip IP) *syscall.RawSockaddr {
-       sa := syscall.RawSockaddrInet6{Len: syscall.SizeofSockaddrInet6, Family: syscall.AF_INET6}
+func cgoSockaddrInet6(ip IP, zone int) *syscall.RawSockaddr {
+       sa := syscall.RawSockaddrInet6{Len: syscall.SizeofSockaddrInet6, Family: syscall.AF_INET6, Scope_id: uint32(zone)}
        copy(sa.Addr[:], ip)
        return (*syscall.RawSockaddr)(unsafe.Pointer(&sa))
 }
index 8eafa8cbd44f8ef8db28e6adf38e4581a7d80eaf..f634323ed8bcc704953c3f37fa1516771fb9792a 100644 (file)
@@ -211,11 +211,15 @@ func cgoLookupPTR(addr string) ([]string, error, bool) {
        acquireThread()
        defer releaseThread()
 
-       ip := ParseIP(addr)
+       var zone string
+       ip := parseIPv4(addr)
+       if ip == nil {
+               ip, zone = parseIPv6(addr, true)
+       }
        if ip == nil {
                return nil, &DNSError{Err: "invalid address", Name: addr}, true
        }
-       sa, salen := cgoSockaddr(ip)
+       sa, salen := cgoSockaddr(ip, zone)
        if sa == nil {
                return nil, &DNSError{Err: "invalid address " + ip.String(), Name: addr}, true
        }
@@ -247,20 +251,15 @@ func cgoLookupPTR(addr string) ([]string, error, bool) {
                        break
                }
        }
-       // Add trailing dot to match pure Go reverse resolver
-       // and all other lookup routines. See golang.org/issue/12189.
-       if len(b) > 0 && b[len(b)-1] != '.' {
-               b = append(b, '.')
-       }
-       return []string{string(b)}, nil, true
+       return []string{absDomainName(b)}, nil, true
 }
 
-func cgoSockaddr(ip IP) (*syscall.RawSockaddr, syscall.Socklen_t) {
+func cgoSockaddr(ip IP, zone string) (*syscall.RawSockaddr, syscall.Socklen_t) {
        if ip4 := ip.To4(); ip4 != nil {
                return cgoSockaddrInet4(ip4), syscall.Socklen_t(syscall.SizeofSockaddrInet4)
        }
        if ip6 := ip.To16(); ip6 != nil {
-               return cgoSockaddrInet6(ip6), syscall.Socklen_t(syscall.SizeofSockaddrInet6)
+               return cgoSockaddrInet6(ip6, zoneToInt(zone)), syscall.Socklen_t(syscall.SizeofSockaddrInet6)
        }
        return nil, 0
 }
index c92e579d7e6852e4e929a2c1dc8a1e7dfe69789d..ddaa978f4f63c5b5286c941b3bf4411017383363 100644 (file)
@@ -9,7 +9,6 @@ package net
 import (
        "os"
        "runtime"
-       "strconv"
        "sync"
        "syscall"
 )
@@ -293,7 +292,7 @@ func goDebugNetDNS() (dnsMode string, debugLevel int) {
                        return
                }
                if '0' <= s[0] && s[0] <= '9' {
-                       debugLevel, _ = strconv.Atoi(s)
+                       debugLevel, _, _ = dtoi(s, 0)
                } else {
                        dnsMode = s
                }
index cb4ec216d53f3c3497f9a63f59ed4fdc19c450b7..193776fe41359f9906c5e22896f479f522c824f0 100644 (file)
@@ -57,6 +57,11 @@ type Dialer struct {
        // If zero, keep-alives are not enabled. Network protocols
        // that do not support keep-alives ignore this field.
        KeepAlive time.Duration
+
+       // Cancel is an optional channel whose closure indicates that
+       // the dial should be canceled. Not all types of dials support
+       // cancelation.
+       Cancel <-chan struct{}
 }
 
 // Return either now+Timeout or Deadline, whichever comes first.
@@ -165,12 +170,14 @@ func resolveAddrList(op, net, addr string, deadline time.Time) (addrList, error)
 // in square brackets as in "[::1]:80" or "[ipv6-host%zone]:80".
 // The functions JoinHostPort and SplitHostPort manipulate addresses
 // in this form.
+// If the host is empty, as in ":80", the local system is assumed.
 //
 // Examples:
 //     Dial("tcp", "12.34.56.78:80")
 //     Dial("tcp", "google.com:http")
 //     Dial("tcp", "[2001:db8::1]:http")
 //     Dial("tcp", "[fe80::1%lo0]:80")
+//     Dial("tcp", ":80")
 //
 // For IP networks, the network must be "ip", "ip4" or "ip6" followed
 // by a colon and a protocol number or name and the addr must be a
@@ -361,7 +368,7 @@ func dialSingle(ctx *dialContext, ra Addr, deadline time.Time) (c Conn, err erro
        switch ra := ra.(type) {
        case *TCPAddr:
                la, _ := la.(*TCPAddr)
-               c, err = testHookDialTCP(ctx.network, la, ra, deadline)
+               c, err = testHookDialTCP(ctx.network, la, ra, deadline, ctx.Cancel)
        case *UDPAddr:
                la, _ := la.(*UDPAddr)
                c, err = dialUDP(ctx.network, la, ra, deadline)
@@ -383,7 +390,10 @@ func dialSingle(ctx *dialContext, ra Addr, deadline time.Time) (c Conn, err erro
 // Listen announces on the local network address laddr.
 // The network net must be a stream-oriented network: "tcp", "tcp4",
 // "tcp6", "unix" or "unixpacket".
-// See Dial for the syntax of laddr.
+// For TCP and UDP, the syntax of laddr is "host:port", like "127.0.0.1:8080".
+// If host is omitted, as in ":8080", Listen listens on all available interfaces
+// instead of just the interface with the given host address.
+// See Dial for more details about address syntax.
 func Listen(net, laddr string) (Listener, error) {
        addrs, err := resolveAddrList("listen", net, laddr, noDeadline)
        if err != nil {
@@ -407,6 +417,9 @@ func Listen(net, laddr string) (Listener, error) {
 // ListenPacket announces on the local network address laddr.
 // The network net must be a packet-oriented network: "udp", "udp4",
 // "udp6", "ip", "ip4", "ip6" or "unixgram".
+// For TCP and UDP, the syntax of laddr is "host:port", like "127.0.0.1:8080".
+// If host is omitted, as in ":8080", ListenPacket listens on all available interfaces
+// instead of just the interface with the given host address.
 // See Dial for the syntax of laddr.
 func ListenPacket(net, laddr string) (PacketConn, error) {
        addrs, err := resolveAddrList("listen", net, laddr, noDeadline)
index ed6d7cc42f135d7a38e204e42e568318efbcf8f6..2311b108241d3d552d4c034d7370f20e68f59392 100644 (file)
@@ -5,6 +5,7 @@
 package net
 
 import (
+       "internal/testenv"
        "io"
        "net/internal/socktest"
        "runtime"
@@ -236,8 +237,8 @@ const (
 // In some environments, the slow IPs may be explicitly unreachable, and fail
 // more quickly than expected. This test hook prevents dialTCP from returning
 // before the deadline.
-func slowDialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, error) {
-       c, err := dialTCP(net, laddr, raddr, deadline)
+func slowDialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time, cancel <-chan struct{}) (*TCPConn, error) {
+       c, err := dialTCP(net, laddr, raddr, deadline, cancel)
        if ParseIP(slowDst4).Equal(raddr.IP) || ParseIP(slowDst6).Equal(raddr.IP) {
                time.Sleep(deadline.Sub(time.Now()))
        }
@@ -509,6 +510,9 @@ func TestDialerFallbackDelay(t *testing.T) {
 }
 
 func TestDialSerialAsyncSpuriousConnection(t *testing.T) {
+       if runtime.GOOS == "plan9" {
+               t.Skip("skipping on plan9; no deadline support, golang.org/issue/11932")
+       }
        ln, err := newLocalListener("tcp")
        if err != nil {
                t.Fatal(err)
@@ -643,7 +647,7 @@ func TestDialerDualStack(t *testing.T) {
                }
        }
 
-       var timeout = 100*time.Millisecond + closedPortDelay
+       var timeout = 150*time.Millisecond + closedPortDelay
        for _, dualstack := range []bool{false, true} {
                dss, err := newDualStackServer([]streamListener{
                        {network: "tcp4", address: "127.0.0.1"},
@@ -713,3 +717,67 @@ func TestDialerKeepAlive(t *testing.T) {
                }
        }
 }
+
+func TestDialCancel(t *testing.T) {
+       if runtime.GOOS == "plan9" || runtime.GOOS == "nacl" {
+               // plan9 is not implemented and nacl doesn't have
+               // external network access.
+               t.Skipf("skipping on %s", runtime.GOOS)
+       }
+       onGoBuildFarm := testenv.Builder() != ""
+       if testing.Short() && !onGoBuildFarm {
+               t.Skip("skipping in short mode")
+       }
+
+       blackholeIPPort := JoinHostPort(slowDst4, "1234")
+       if !supportsIPv4 {
+               blackholeIPPort = JoinHostPort(slowDst6, "1234")
+       }
+
+       ticker := time.NewTicker(10 * time.Millisecond)
+       defer ticker.Stop()
+
+       const cancelTick = 5 // the timer tick we cancel the dial at
+       const timeoutTick = 100
+
+       var d Dialer
+       cancel := make(chan struct{})
+       d.Cancel = cancel
+       errc := make(chan error, 1)
+       connc := make(chan Conn, 1)
+       go func() {
+               if c, err := d.Dial("tcp", blackholeIPPort); err != nil {
+                       errc <- err
+               } else {
+                       connc <- c
+               }
+       }()
+       ticks := 0
+       for {
+               select {
+               case <-ticker.C:
+                       ticks++
+                       if ticks == cancelTick {
+                               close(cancel)
+                       }
+                       if ticks == timeoutTick {
+                               t.Fatal("timeout waiting for dial to fail")
+                       }
+               case c := <-connc:
+                       c.Close()
+                       t.Fatal("unexpected successful connection")
+               case err := <-errc:
+                       if perr := parseDialError(err); perr != nil {
+                               t.Error(perr)
+                       }
+                       if ticks < cancelTick {
+                               t.Fatalf("dial error after %d ticks (%d before cancel sent): %v",
+                                       ticks, cancelTick-ticks, err)
+                       }
+                       if oe, ok := err.(*OpError); !ok || oe.Err != errCanceled {
+                               t.Fatalf("dial error = %v (%T); want OpError with Err == errCanceled", err, err)
+                       }
+                       return // success.
+               }
+       }
+}
index ce48521bc601933a1113890cb13b95e04115f33c..5dc2a0368ceeb242593f306884a1ba25a94aecb4 100644 (file)
@@ -40,15 +40,20 @@ func reverseaddr(addr string) (arpa string, err error) {
 func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs []dnsRR, err error) {
        addrs = make([]dnsRR, 0, len(dns.answer))
 
-       if dns.rcode == dnsRcodeNameError && dns.recursion_available {
+       if dns.rcode == dnsRcodeNameError {
                return "", nil, &DNSError{Err: errNoSuchHost.Error(), Name: name, Server: server}
        }
        if dns.rcode != dnsRcodeSuccess {
                // None of the error codes make sense
                // for the query we sent.  If we didn't get
                // a name error and we didn't get success,
-               // the server is behaving incorrectly.
-               return "", nil, &DNSError{Err: "server misbehaving", Name: name, Server: server}
+               // the server is behaving incorrectly or
+               // having temporary trouble.
+               err := &DNSError{Err: "server misbehaving", Name: name, Server: server}
+               if dns.rcode == dnsRcodeServerFailure {
+                       err.IsTemporary = true
+               }
+               return "", nil, err
        }
 
        // Look for the name.
@@ -156,6 +161,28 @@ func isDomainName(s string) bool {
        return ok
 }
 
+// absDomainName returns an absoulte domain name which ends with a
+// trailing dot to match pure Go reverse resolver and all other lookup
+// routines.
+// See golang.org/issue/12189.
+// But we don't want to add dots for local names from /etc/hosts.
+// It's hard to tell so we settle on the heuristic that names without dots
+// (like "localhost" or "myhost") do not get trailing dots, but any other
+// names do.
+func absDomainName(b []byte) string {
+       hasDots := false
+       for _, x := range b {
+               if x == '.' {
+                       hasDots = true
+                       break
+               }
+       }
+       if hasDots && b[len(b)-1] != '.' {
+               b = append(b, '.')
+       }
+       return string(b)
+}
+
 // An SRV represents a single DNS SRV record.
 type SRV struct {
        Target   string
index 3ab2b836ef60a3795c02b668704c80dfe73e8a0b..7308fb03fa108e2c899bf1d630426dc71939c994 100644 (file)
@@ -67,3 +67,51 @@ func testWeighting(t *testing.T, margin float64) {
 func TestWeighting(t *testing.T) {
        testWeighting(t, 0.05)
 }
+
+// Issue 8434: verify that Temporary returns true on an error when rcode
+// is SERVFAIL
+func TestIssue8434(t *testing.T) {
+       msg := &dnsMsg{
+               dnsMsgHdr: dnsMsgHdr{
+                       rcode: dnsRcodeServerFailure,
+               },
+       }
+
+       _, _, err := answer("golang.org", "foo:53", msg, uint16(dnsTypeSRV))
+       if err == nil {
+               t.Fatal("expected an error")
+       }
+       if ne, ok := err.(Error); !ok {
+               t.Fatalf("err = %#v; wanted something supporting net.Error", err)
+       } else if !ne.Temporary() {
+               t.Fatalf("Temporary = false for err = %#v; want Temporary == true", err)
+       }
+       if de, ok := err.(*DNSError); !ok {
+               t.Fatalf("err = %#v; wanted a *net.DNSError", err)
+       } else if !de.IsTemporary {
+               t.Fatalf("IsTemporary = false for err = %#v; want IsTemporary == true", err)
+       }
+}
+
+// Issue 12778: verify that NXDOMAIN without RA bit errors as
+// "no such host" and not "server misbehaving"
+func TestIssue12778(t *testing.T) {
+       msg := &dnsMsg{
+               dnsMsgHdr: dnsMsgHdr{
+                       rcode:               dnsRcodeNameError,
+                       recursion_available: false,
+               },
+       }
+
+       _, _, err := answer("golang.org", "foo:53", msg, uint16(dnsTypeSRV))
+       if err == nil {
+               t.Fatal("expected an error")
+       }
+       de, ok := err.(*DNSError)
+       if !ok {
+               t.Fatalf("err = %#v; wanted a *net.DNSError", err)
+       }
+       if de.Err != errNoSuchHost.Error() {
+               t.Fatalf("Err = %#v; wanted %q", de.Err, errNoSuchHost.Error())
+       }
+}
index c03c1b1159fdc6c58b5f863b063452f0116fb4c6..17188f0024c0c6a1e2244426ea36acba9387a25b 100644 (file)
@@ -20,14 +20,22 @@ import (
        "io"
        "math/rand"
        "os"
-       "strconv"
        "sync"
        "time"
 )
 
+// A dnsDialer provides dialing suitable for DNS queries.
+type dnsDialer interface {
+       dialDNS(string, string) (dnsConn, error)
+}
+
+var testHookDNSDialer = func(d time.Duration) dnsDialer { return &Dialer{Timeout: d} }
+
 // A dnsConn represents a DNS transport endpoint.
 type dnsConn interface {
-       Conn
+       io.Closer
+
+       SetDeadline(time.Time) error
 
        // readDNSResponse reads a DNS response message from the DNS
        // transport endpoint and returns the received DNS response
@@ -122,7 +130,7 @@ func (d *Dialer) dialDNS(network, server string) (dnsConn, error) {
 
 // exchange sends a query on the connection and hopes for a response.
 func exchange(server, name string, qtype uint16, timeout time.Duration) (*dnsMsg, error) {
-       d := Dialer{Timeout: timeout}
+       d := testHookDNSDialer(timeout)
        out := dnsMsg{
                dnsMsgHdr: dnsMsgHdr{
                        recursion_desired: true,
@@ -165,9 +173,6 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, err
        if len(cfg.servers) == 0 {
                return "", nil, &DNSError{Err: "no DNS servers", Name: name}
        }
-       if len(name) >= 256 {
-               return "", nil, &DNSError{Err: "DNS name too long", Name: name}
-       }
        timeout := time.Duration(cfg.timeout) * time.Second
        var lastErr error
        for i := 0; i < cfg.attempts; i++ {
@@ -186,7 +191,11 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, err
                                continue
                        }
                        cname, rrs, err := answer(name, server, msg, qtype)
-                       if err == nil || msg.rcode == dnsRcodeSuccess || msg.rcode == dnsRcodeNameError && msg.recursion_available {
+                       // If answer errored for rcodes dnsRcodeSuccess or dnsRcodeNameError,
+                       // it means the response in msg was not useful and trying another
+                       // server probably won't help. Return now in those cases.
+                       // TODO: indicate this in a more obvious way, such as a field on DNSError?
+                       if err == nil || msg.rcode == dnsRcodeSuccess || msg.rcode == dnsRcodeNameError {
                                return cname, rrs, err
                        }
                        lastErr = err
@@ -374,7 +383,7 @@ func (o hostLookupOrder) String() string {
        if s, ok := lookupOrderName[o]; ok {
                return s
        }
-       return "hostLookupOrder=" + strconv.Itoa(int(o)) + "??"
+       return "hostLookupOrder=" + itoa(int(o)) + "??"
 }
 
 // goLookupHost is the native Go implementation of LookupHost.
@@ -440,7 +449,8 @@ func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err er
        conf := resolvConf.dnsConfig
        resolvConf.mu.RUnlock()
        type racer struct {
-               rrs []dnsRR
+               fqdn string
+               rrs  []dnsRR
                error
        }
        lane := make(chan racer, 1)
@@ -450,13 +460,16 @@ func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err er
                for _, qtype := range qtypes {
                        go func(qtype uint16) {
                                _, rrs, err := tryOneName(conf, fqdn, qtype)
-                               lane <- racer{rrs, err}
+                               lane <- racer{fqdn, rrs, err}
                        }(qtype)
                }
                for range qtypes {
                        racer := <-lane
                        if racer.error != nil {
-                               lastErr = racer.error
+                               // Prefer error for original name.
+                               if lastErr == nil || racer.fqdn == name+"." {
+                                       lastErr = racer.error
+                               }
                                continue
                        }
                        addrs = append(addrs, addrRecordList(racer.rrs)...)
@@ -473,12 +486,12 @@ func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err er
        }
        sortByRFC6724(addrs)
        if len(addrs) == 0 {
-               if lastErr != nil {
-                       return nil, lastErr
-               }
                if order == hostLookupDNSFiles {
                        addrs = goLookupIPFiles(name)
                }
+               if len(addrs) == 0 && lastErr != nil {
+                       return nil, lastErr
+               }
        }
        return addrs, nil
 }
index a999f8f060726b17e268ae1ca7ce90735386b258..934f25b2c94e930b6fd40ecdbc3274fa7c06f1d6 100644 (file)
@@ -80,7 +80,7 @@ func TestSpecialDomainName(t *testing.T) {
 
        server := "8.8.8.8:53"
        for _, tt := range specialDomainNameTests {
-               msg, err := exchange(server, tt.name, tt.qtype, 0)
+               msg, err := exchange(server, tt.name, tt.qtype, 3*time.Second)
                if err != nil {
                        t.Error(err)
                        continue
@@ -378,6 +378,103 @@ func TestGoLookupIPWithResolverConfig(t *testing.T) {
        }
 }
 
+// Test that goLookupIPOrder falls back to the host file when no DNS servers are available.
+func TestGoLookupIPOrderFallbackToFile(t *testing.T) {
+       if testing.Short() || !*testExternal {
+               t.Skip("avoid external network")
+       }
+
+       // Add a config that simulates no dns servers being available.
+       conf, err := newResolvConfTest()
+       if err != nil {
+               t.Fatal(err)
+       }
+       if err := conf.writeAndUpdate([]string{}); err != nil {
+               t.Fatal(err)
+       }
+       conf.tryUpdate(conf.path)
+       // Redirect host file lookups.
+       defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
+       testHookHostsPath = "testdata/hosts"
+
+       for _, order := range []hostLookupOrder{hostLookupFilesDNS, hostLookupDNSFiles} {
+               name := fmt.Sprintf("order %v", order)
+
+               // First ensure that we get an error when contacting a non-existant host.
+               _, err := goLookupIPOrder("notarealhost", order)
+               if err == nil {
+                       t.Errorf("%s: expected error while looking up name not in hosts file", name)
+                       continue
+               }
+
+               // Now check that we get an address when the name appears in the hosts file.
+               addrs, err := goLookupIPOrder("thor", order) // entry is in "testdata/hosts"
+               if err != nil {
+                       t.Errorf("%s: expected to successfully lookup host entry", name)
+                       continue
+               }
+               if len(addrs) != 1 {
+                       t.Errorf("%s: expected exactly one result, but got %v", name, addrs)
+                       continue
+               }
+               if got, want := addrs[0].String(), "127.1.1.1"; got != want {
+                       t.Errorf("%s: address doesn't match expectation. got %v, want %v", name, got, want)
+               }
+       }
+       defer conf.teardown()
+}
+
+// Issue 12712.
+// When using search domains, return the error encountered
+// querying the original name instead of an error encountered
+// querying a generated name.
+func TestErrorForOriginalNameWhenSearching(t *testing.T) {
+       const fqdn = "doesnotexist.domain"
+
+       origTestHookDNSDialer := testHookDNSDialer
+       defer func() { testHookDNSDialer = origTestHookDNSDialer }()
+
+       conf, err := newResolvConfTest()
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer conf.teardown()
+
+       if err := conf.writeAndUpdate([]string{"search servfail"}); err != nil {
+               t.Fatal(err)
+       }
+
+       d := &fakeDNSConn{}
+       testHookDNSDialer = func(time.Duration) dnsDialer { return d }
+
+       d.rh = func(q *dnsMsg) (*dnsMsg, error) {
+               r := &dnsMsg{
+                       dnsMsgHdr: dnsMsgHdr{
+                               id: q.id,
+                       },
+               }
+
+               switch q.question[0].Name {
+               case fqdn + ".servfail.":
+                       r.rcode = dnsRcodeServerFailure
+               default:
+                       r.rcode = dnsRcodeNameError
+               }
+
+               return r, nil
+       }
+
+       _, err = goLookupIP(fqdn)
+       if err == nil {
+               t.Fatal("expected an error")
+       }
+
+       want := &DNSError{Name: fqdn, Err: errNoSuchHost.Error()}
+       if err, ok := err.(*DNSError); !ok || err.Name != want.Name || err.Err != want.Err {
+               t.Errorf("got %v; want %v", err, want)
+       }
+}
+
 func BenchmarkGoLookupIP(b *testing.B) {
        testHookUninstaller.Do(uninstallTestHooks)
 
@@ -415,3 +512,37 @@ func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
                goLookupIP("www.example.com")
        }
 }
+
+type fakeDNSConn struct {
+       // last query
+       qmu sync.Mutex // guards q
+       q   *dnsMsg
+       // reply handler
+       rh func(*dnsMsg) (*dnsMsg, error)
+}
+
+func (f *fakeDNSConn) dialDNS(n, s string) (dnsConn, error) {
+       return f, nil
+}
+
+func (f *fakeDNSConn) Close() error {
+       return nil
+}
+
+func (f *fakeDNSConn) SetDeadline(time.Time) error {
+       return nil
+}
+
+func (f *fakeDNSConn) writeDNSQuery(q *dnsMsg) error {
+       f.qmu.Lock()
+       defer f.qmu.Unlock()
+       f.q = q
+       return nil
+}
+
+func (f *fakeDNSConn) readDNSResponse() (*dnsMsg, error) {
+       f.qmu.Lock()
+       q := f.q
+       f.qmu.Unlock()
+       return f.rh(q)
+}
index 6ecaa9482304f7b1b1a9eb90814e60350a9192c9..93078fe849982bb440ed9f7cec8d700fcd431fc8 100644 (file)
@@ -691,6 +691,9 @@ func packRR(rr dnsRR, msg []byte, off int) (off2 int, ok bool) {
        // off1 is end of header
        // off2 is end of rr
        off1, ok = packStruct(rr.Header(), msg, off)
+       if !ok {
+               return len(msg), false
+       }
        off2, ok = packStruct(rr, msg, off)
        if !ok {
                return len(msg), false
index bf95ff6108cb1904e72b185890b3954b622d07c6..1aab14c4499ae3950bc5cb98aee524de4e96dcbc 100644 (file)
@@ -93,7 +93,7 @@ second:
                goto third
        }
        switch nestedErr {
-       case errClosing, errMissingAddress:
+       case errCanceled, errClosing, errMissingAddress:
                return nil
        }
        return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@@ -116,8 +116,10 @@ var dialErrorTests = []struct {
        {"tcp", "no-such-name:80"},
        {"tcp", "mh/astro/r70:http"},
 
-       {"tcp", "127.0.0.1:0"},
-       {"udp", "127.0.0.1:0"},
+       {"tcp", JoinHostPort("127.0.0.1", "-1")},
+       {"tcp", JoinHostPort("127.0.0.1", "123456789")},
+       {"udp", JoinHostPort("127.0.0.1", "-1")},
+       {"udp", JoinHostPort("127.0.0.1", "123456789")},
        {"ip:icmp", "127.0.0.1"},
 
        {"unix", "/path/to/somewhere"},
@@ -145,10 +147,23 @@ func TestDialError(t *testing.T) {
        for i, tt := range dialErrorTests {
                c, err := d.Dial(tt.network, tt.address)
                if err == nil {
-                       t.Errorf("#%d: should fail; %s:%s->%s", i, tt.network, c.LocalAddr(), c.RemoteAddr())
+                       t.Errorf("#%d: should fail; %s:%s->%s", i, c.LocalAddr().Network(), c.LocalAddr(), c.RemoteAddr())
                        c.Close()
                        continue
                }
+               if tt.network == "tcp" || tt.network == "udp" {
+                       nerr := err
+                       if op, ok := nerr.(*OpError); ok {
+                               nerr = op.Err
+                       }
+                       if sys, ok := nerr.(*os.SyscallError); ok {
+                               nerr = sys.Err
+                       }
+                       if nerr == errOpNotSupported {
+                               t.Errorf("#%d: should fail without %v; %s:%s->", i, nerr, tt.network, tt.address)
+                               continue
+                       }
+               }
                if c != nil {
                        t.Errorf("Dial returned non-nil interface %T(%v) with err != nil", c, c)
                }
@@ -198,7 +213,8 @@ var listenErrorTests = []struct {
        {"tcp", "no-such-name:80"},
        {"tcp", "mh/astro/r70:http"},
 
-       {"tcp", "127.0.0.1:0"},
+       {"tcp", JoinHostPort("127.0.0.1", "-1")},
+       {"tcp", JoinHostPort("127.0.0.1", "123456789")},
 
        {"unix", "/path/to/somewhere"},
        {"unixpacket", "/path/to/somewhere"},
@@ -223,10 +239,23 @@ func TestListenError(t *testing.T) {
        for i, tt := range listenErrorTests {
                ln, err := Listen(tt.network, tt.address)
                if err == nil {
-                       t.Errorf("#%d: should fail; %s:%s->", i, tt.network, ln.Addr())
+                       t.Errorf("#%d: should fail; %s:%s->", i, ln.Addr().Network(), ln.Addr())
                        ln.Close()
                        continue
                }
+               if tt.network == "tcp" {
+                       nerr := err
+                       if op, ok := nerr.(*OpError); ok {
+                               nerr = op.Err
+                       }
+                       if sys, ok := nerr.(*os.SyscallError); ok {
+                               nerr = sys.Err
+                       }
+                       if nerr == errOpNotSupported {
+                               t.Errorf("#%d: should fail without %v; %s:%s->", i, nerr, tt.network, tt.address)
+                               continue
+                       }
+               }
                if ln != nil {
                        t.Errorf("Listen returned non-nil interface %T(%v) with err != nil", ln, ln)
                }
@@ -246,6 +275,9 @@ var listenPacketErrorTests = []struct {
        {"udp", "127.0.0.1:☺"},
        {"udp", "no-such-name:80"},
        {"udp", "mh/astro/r70:http"},
+
+       {"udp", JoinHostPort("127.0.0.1", "-1")},
+       {"udp", JoinHostPort("127.0.0.1", "123456789")},
 }
 
 func TestListenPacketError(t *testing.T) {
@@ -263,7 +295,7 @@ func TestListenPacketError(t *testing.T) {
        for i, tt := range listenPacketErrorTests {
                c, err := ListenPacket(tt.network, tt.address)
                if err == nil {
-                       t.Errorf("#%d: should fail; %s:%s->", i, tt.network, c.LocalAddr())
+                       t.Errorf("#%d: should fail; %s:%s->", i, c.LocalAddr().Network(), c.LocalAddr())
                        c.Close()
                        continue
                }
@@ -381,7 +413,7 @@ second:
                goto third
        }
        switch nestedErr {
-       case errClosing, errTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
+       case errCanceled, errClosing, errTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
                return nil
        }
        return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
index 32766f53b58ea9ccd12eee4232249ee38dc751b2..cec88609d06c82ac5984aca7e4537dbcde44ec95 100644 (file)
@@ -171,6 +171,14 @@ func (fd *netFD) Close() error {
        if !fd.ok() {
                return syscall.EINVAL
        }
+       if fd.net == "tcp" {
+               // The following line is required to unblock Reads.
+               // For some reason, WriteString returns an error:
+               // "write /net/tcp/39/listen: inappropriate use of fd"
+               // But without it, Reads on dead conns hang forever.
+               // See Issue 9554.
+               fd.ctl.WriteString("hangup")
+       }
        err := fd.ctl.Close()
        if fd.data != nil {
                if err1 := fd.data.Close(); err1 != nil && err == nil {
index 465023fb23dbb899777d18b4ef12285b45f2e2cd..ff498c2bff0c0b9cfb3b7423ab7928f5f0dfe1f2 100644 (file)
@@ -68,7 +68,7 @@ func (fd *netFD) name() string {
        return fd.net + ":" + ls + "->" + rs
 }
 
-func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
+func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-chan struct{}) error {
        // Do not need to call fd.writeLock here,
        // because fd is not yet accessible to user,
        // so no concurrent operations are possible.
@@ -102,6 +102,19 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
                fd.setWriteDeadline(deadline)
                defer fd.setWriteDeadline(noDeadline)
        }
+       if cancel != nil {
+               done := make(chan bool)
+               defer close(done)
+               go func() {
+                       select {
+                       case <-cancel:
+                               // Force the runtime's poller to immediately give
+                               // up waiting for writability.
+                               fd.setWriteDeadline(aLongTimeAgo)
+                       case <-done:
+                       }
+               }()
+       }
        for {
                // Performing multiple connect system calls on a
                // non-blocking socket under Unix variants does not
@@ -112,6 +125,11 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
                // succeeded or failed. See issue 7474 for further
                // details.
                if err := fd.pd.WaitWrite(); err != nil {
+                       select {
+                       case <-cancel:
+                               return errCanceled
+                       default:
+                       }
                        return err
                }
                nerr, err := getsockoptIntFunc(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
index 205daff9e4607ec22d56a460335c136906fb404d..fd50d772d60d95846f981e09487b7fd281f04438 100644 (file)
@@ -5,6 +5,7 @@
 package net
 
 import (
+       "internal/race"
        "os"
        "runtime"
        "sync"
@@ -208,7 +209,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro
                s.req <- ioSrvReq{o, nil}
                <-o.errc
        }
-       // Wait for cancellation to complete.
+       // Wait for cancelation to complete.
        fd.pd.WaitCanceled(int(o.mode))
        if o.errno != 0 {
                err = syscall.Errno(o.errno)
@@ -217,8 +218,8 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro
                }
                return 0, err
        }
-       // We issued cancellation request. But, it seems, IO operation succeeded
-       // before cancellation request run. We need to treat IO operation as
+       // We issued a cancelation request. But, it seems, IO operation succeeded
+       // before the cancelation request run. We need to treat the IO operation as
        // succeeded (the bytes are actually sent/recv from network).
        return int(o.qty), nil
 }
@@ -319,7 +320,7 @@ func (fd *netFD) setAddr(laddr, raddr Addr) {
        runtime.SetFinalizer(fd, (*netFD).Close)
 }
 
-func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
+func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-chan struct{}) error {
        // Do not need to call fd.writeLock here,
        // because fd is not yet accessible to user,
        // so no concurrent operations are possible.
@@ -350,14 +351,32 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
        // Call ConnectEx API.
        o := &fd.wop
        o.sa = ra
+       if cancel != nil {
+               done := make(chan struct{})
+               defer close(done)
+               go func() {
+                       select {
+                       case <-cancel:
+                               // Force the runtime's poller to immediately give
+                               // up waiting for writability.
+                               fd.setWriteDeadline(aLongTimeAgo)
+                       case <-done:
+                       }
+               }()
+       }
        _, err := wsrv.ExecIO(o, "ConnectEx", func(o *operation) error {
                return connectExFunc(o.fd.sysfd, o.sa, nil, 0, nil, &o.o)
        })
        if err != nil {
-               if _, ok := err.(syscall.Errno); ok {
-                       err = os.NewSyscallError("connectex", err)
+               select {
+               case <-cancel:
+                       return errCanceled
+               default:
+                       if _, ok := err.(syscall.Errno); ok {
+                               err = os.NewSyscallError("connectex", err)
+                       }
+                       return err
                }
-               return err
        }
        // Refresh socket properties.
        return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd))))
@@ -461,8 +480,8 @@ func (fd *netFD) Read(buf []byte) (int, error) {
        n, err := rsrv.ExecIO(o, "WSARecv", func(o *operation) error {
                return syscall.WSARecv(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, &o.o, nil)
        })
-       if raceenabled {
-               raceAcquire(unsafe.Pointer(&ioSync))
+       if race.Enabled {
+               race.Acquire(unsafe.Pointer(&ioSync))
        }
        err = fd.eofError(n, err)
        if _, ok := err.(syscall.Errno); ok {
@@ -504,8 +523,8 @@ func (fd *netFD) Write(buf []byte) (int, error) {
                return 0, err
        }
        defer fd.writeUnlock()
-       if raceenabled {
-               raceReleaseMerge(unsafe.Pointer(&ioSync))
+       if race.Enabled {
+               race.ReleaseMerge(unsafe.Pointer(&ioSync))
        }
        o := &fd.wop
        o.InitBuf(buf)
index 003dbb2ecb759212fec1b0e25f9bf2c36d6ebb98..6566ce21a1f6fd7c26fbf9733cfcf99bee4b86c4 100644 (file)
@@ -8,158 +8,222 @@ import (
        "os"
        "reflect"
        "runtime"
+       "sync"
        "testing"
 )
 
-type listenerFile interface {
-       Listener
-       File() (f *os.File, err error)
-}
-
-type packetConnFile interface {
-       PacketConn
-       File() (f *os.File, err error)
-}
+// The full stack test cases for IPConn have been moved to the
+// following:
+//      golang.org/x/net/ipv4
+//      golang.org/x/net/ipv6
+//      golang.org/x/net/icmp
 
-type connFile interface {
-       Conn
-       File() (f *os.File, err error)
+var fileConnTests = []struct {
+       network string
+}{
+       {"tcp"},
+       {"udp"},
+       {"unix"},
+       {"unixpacket"},
 }
 
-func testFileListener(t *testing.T, net, laddr string) {
-       l, err := Listen(net, laddr)
-       if err != nil {
-               t.Fatal(err)
-       }
-       defer l.Close()
-       lf := l.(listenerFile)
-       f, err := lf.File()
-       if err != nil {
-               t.Fatal(err)
-       }
-       c, err := FileListener(f)
-       if err != nil {
-               t.Fatal(err)
-       }
-       if !reflect.DeepEqual(l.Addr(), c.Addr()) {
-               t.Fatalf("got %#v; want%#v", l.Addr(), c.Addr())
-       }
-       if err := c.Close(); err != nil {
-               t.Fatal(err)
-       }
-       if err := f.Close(); err != nil {
-               t.Fatal(err)
+func TestFileConn(t *testing.T) {
+       switch runtime.GOOS {
+       case "nacl", "plan9", "windows":
+               t.Skipf("not supported on %s", runtime.GOOS)
        }
-}
 
-var fileListenerTests = []struct {
-       net   string
-       laddr string
-}{
-       {net: "tcp", laddr: ":0"},
-       {net: "tcp", laddr: "0.0.0.0:0"},
-       {net: "tcp", laddr: "[::ffff:0.0.0.0]:0"},
-       {net: "tcp", laddr: "[::]:0"},
+       for _, tt := range fileConnTests {
+               if !testableNetwork(tt.network) {
+                       t.Logf("skipping %s test", tt.network)
+                       continue
+               }
 
-       {net: "tcp", laddr: "127.0.0.1:0"},
-       {net: "tcp", laddr: "[::ffff:127.0.0.1]:0"},
-       {net: "tcp", laddr: "[::1]:0"},
+               var network, address string
+               switch tt.network {
+               case "udp":
+                       c, err := newLocalPacketListener(tt.network)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       defer c.Close()
+                       network = c.LocalAddr().Network()
+                       address = c.LocalAddr().String()
+               default:
+                       handler := func(ls *localServer, ln Listener) {
+                               c, err := ln.Accept()
+                               if err != nil {
+                                       return
+                               }
+                               defer c.Close()
+                               var b [1]byte
+                               c.Read(b[:])
+                       }
+                       ls, err := newLocalServer(tt.network)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       defer ls.teardown()
+                       if err := ls.buildup(handler); err != nil {
+                               t.Fatal(err)
+                       }
+                       network = ls.Listener.Addr().Network()
+                       address = ls.Listener.Addr().String()
+               }
 
-       {net: "tcp4", laddr: ":0"},
-       {net: "tcp4", laddr: "0.0.0.0:0"},
-       {net: "tcp4", laddr: "[::ffff:0.0.0.0]:0"},
+               c1, err := Dial(network, address)
+               if err != nil {
+                       if perr := parseDialError(err); perr != nil {
+                               t.Error(perr)
+                       }
+                       t.Fatal(err)
+               }
+               addr := c1.LocalAddr()
 
-       {net: "tcp4", laddr: "127.0.0.1:0"},
-       {net: "tcp4", laddr: "[::ffff:127.0.0.1]:0"},
+               var f *os.File
+               switch c1 := c1.(type) {
+               case *TCPConn:
+                       f, err = c1.File()
+               case *UDPConn:
+                       f, err = c1.File()
+               case *UnixConn:
+                       f, err = c1.File()
+               }
+               if err := c1.Close(); err != nil {
+                       if perr := parseCloseError(err); perr != nil {
+                               t.Error(perr)
+                       }
+                       t.Error(err)
+               }
+               if err != nil {
+                       if perr := parseCommonError(err); perr != nil {
+                               t.Error(perr)
+                       }
+                       t.Fatal(err)
+               }
 
-       {net: "tcp6", laddr: ":0"},
-       {net: "tcp6", laddr: "[::]:0"},
+               c2, err := FileConn(f)
+               if err := f.Close(); err != nil {
+                       t.Error(err)
+               }
+               if err != nil {
+                       if perr := parseCommonError(err); perr != nil {
+                               t.Error(perr)
+                       }
+                       t.Fatal(err)
+               }
+               defer c2.Close()
 
-       {net: "tcp6", laddr: "[::1]:0"},
+               if _, err := c2.Write([]byte("FILECONN TEST")); err != nil {
+                       if perr := parseWriteError(err); perr != nil {
+                               t.Error(perr)
+                       }
+                       t.Fatal(err)
+               }
+               if !reflect.DeepEqual(c2.LocalAddr(), addr) {
+                       t.Fatalf("got %#v; want %#v", c2.LocalAddr(), addr)
+               }
+       }
+}
 
-       {net: "unix", laddr: "@gotest/net"},
-       {net: "unixpacket", laddr: "@gotest/net"},
+var fileListenerTests = []struct {
+       network string
+}{
+       {"tcp"},
+       {"unix"},
+       {"unixpacket"},
 }
 
 func TestFileListener(t *testing.T) {
        switch runtime.GOOS {
-       case "nacl", "windows":
+       case "nacl", "plan9", "windows":
                t.Skipf("not supported on %s", runtime.GOOS)
        }
 
        for _, tt := range fileListenerTests {
-               if !testableListenArgs(tt.net, tt.laddr, "") {
-                       t.Logf("skipping %s test", tt.net+" "+tt.laddr)
+               if !testableNetwork(tt.network) {
+                       t.Logf("skipping %s test", tt.network)
                        continue
                }
-               testFileListener(t, tt.net, tt.laddr)
-       }
-}
 
-func testFilePacketConn(t *testing.T, pcf packetConnFile, listen bool) {
-       f, err := pcf.File()
-       if err != nil {
-               t.Fatal(err)
-       }
-       c, err := FilePacketConn(f)
-       if err != nil {
-               t.Fatal(err)
-       }
-       if !reflect.DeepEqual(pcf.LocalAddr(), c.LocalAddr()) {
-               t.Fatalf("got %#v; want %#v", pcf.LocalAddr(), c.LocalAddr())
-       }
-       if listen {
-               if _, err := c.WriteTo([]byte{}, c.LocalAddr()); err != nil {
+               ln1, err := newLocalListener(tt.network)
+               if err != nil {
                        t.Fatal(err)
                }
-       }
-       if err := c.Close(); err != nil {
-               t.Fatal(err)
-       }
-       if err := f.Close(); err != nil {
-               t.Fatal(err)
-       }
-}
+               switch tt.network {
+               case "unix", "unixpacket":
+                       defer os.Remove(ln1.Addr().String())
+               }
+               addr := ln1.Addr()
 
-func testFilePacketConnListen(t *testing.T, net, laddr string) {
-       l, err := ListenPacket(net, laddr)
-       if err != nil {
-               t.Fatal(err)
-       }
-       testFilePacketConn(t, l.(packetConnFile), true)
-       if err := l.Close(); err != nil {
-               t.Fatal(err)
-       }
-}
+               var f *os.File
+               switch ln1 := ln1.(type) {
+               case *TCPListener:
+                       f, err = ln1.File()
+               case *UnixListener:
+                       f, err = ln1.File()
+               }
+               switch tt.network {
+               case "unix", "unixpacket":
+                       defer ln1.Close() // UnixListener.Close calls syscall.Unlink internally
+               default:
+                       if err := ln1.Close(); err != nil {
+                               t.Error(err)
+                       }
+               }
+               if err != nil {
+                       if perr := parseCommonError(err); perr != nil {
+                               t.Error(perr)
+                       }
+                       t.Fatal(err)
+               }
 
-func testFilePacketConnDial(t *testing.T, net, raddr string) {
-       c, err := Dial(net, raddr)
-       if err != nil {
-               t.Fatal(err)
-       }
-       testFilePacketConn(t, c.(packetConnFile), false)
-       if err := c.Close(); err != nil {
-               t.Fatal(err)
+               ln2, err := FileListener(f)
+               if err := f.Close(); err != nil {
+                       t.Error(err)
+               }
+               if err != nil {
+                       if perr := parseCommonError(err); perr != nil {
+                               t.Error(perr)
+                       }
+                       t.Fatal(err)
+               }
+               defer ln2.Close()
+
+               var wg sync.WaitGroup
+               wg.Add(1)
+               go func() {
+                       defer wg.Done()
+                       c, err := Dial(ln2.Addr().Network(), ln2.Addr().String())
+                       if err != nil {
+                               if perr := parseDialError(err); perr != nil {
+                                       t.Error(perr)
+                               }
+                               t.Error(err)
+                               return
+                       }
+                       c.Close()
+               }()
+               c, err := ln2.Accept()
+               if err != nil {
+                       if perr := parseAcceptError(err); perr != nil {
+                               t.Error(perr)
+                       }
+                       t.Fatal(err)
+               }
+               c.Close()
+               wg.Wait()
+               if !reflect.DeepEqual(ln2.Addr(), addr) {
+                       t.Fatalf("got %#v; want %#v", ln2.Addr(), addr)
+               }
        }
 }
 
 var filePacketConnTests = []struct {
-       net  string
-       addr string
+       network string
 }{
-       {net: "udp", addr: "127.0.0.1:0"},
-       {net: "udp", addr: "[::ffff:127.0.0.1]:0"},
-       {net: "udp", addr: "[::1]:0"},
-
-       {net: "udp4", addr: "127.0.0.1:0"},
-       {net: "udp4", addr: "[::ffff:127.0.0.1]:0"},
-
-       {net: "udp6", addr: "[::1]:0"},
-
-       // TODO(mikioh,bradfitz): reenable once 10730 is fixed
-       // {net: "ip4:icmp", addr: "127.0.0.1"},
-
-       {net: "unixgram", addr: "@gotest3/net"},
+       {"udp"},
+       {"unixgram"},
 }
 
 func TestFilePacketConn(t *testing.T) {
@@ -169,25 +233,61 @@ func TestFilePacketConn(t *testing.T) {
        }
 
        for _, tt := range filePacketConnTests {
-               if !testableListenArgs(tt.net, tt.addr, "") {
-                       t.Logf("skipping %s test", tt.net+" "+tt.addr)
+               if !testableNetwork(tt.network) {
+                       t.Logf("skipping %s test", tt.network)
                        continue
                }
-               if os.Getuid() != 0 && tt.net == "ip4:icmp" {
-                       t.Log("skipping test; must be root")
-                       continue
+
+               c1, err := newLocalPacketListener(tt.network)
+               if err != nil {
+                       t.Fatal(err)
                }
-               testFilePacketConnListen(t, tt.net, tt.addr)
-               switch tt.net {
-               case "udp", "udp4", "udp6":
-                       host, _, err := SplitHostPort(tt.addr)
-                       if err != nil {
-                               t.Error(err)
-                               continue
+               switch tt.network {
+               case "unixgram":
+                       defer os.Remove(c1.LocalAddr().String())
+               }
+               addr := c1.LocalAddr()
+
+               var f *os.File
+               switch c1 := c1.(type) {
+               case *UDPConn:
+                       f, err = c1.File()
+               case *UnixConn:
+                       f, err = c1.File()
+               }
+               if err := c1.Close(); err != nil {
+                       if perr := parseCloseError(err); perr != nil {
+                               t.Error(perr)
                        }
-                       testFilePacketConnDial(t, tt.net, JoinHostPort(host, "12345"))
-               case "ip4:icmp":
-                       testFilePacketConnDial(t, tt.net, tt.addr)
+                       t.Error(err)
+               }
+               if err != nil {
+                       if perr := parseCommonError(err); perr != nil {
+                               t.Error(perr)
+                       }
+                       t.Fatal(err)
+               }
+
+               c2, err := FilePacketConn(f)
+               if err := f.Close(); err != nil {
+                       t.Error(err)
+               }
+               if err != nil {
+                       if perr := parseCommonError(err); perr != nil {
+                               t.Error(perr)
+                       }
+                       t.Fatal(err)
+               }
+               defer c2.Close()
+
+               if _, err := c2.WriteTo([]byte("FILEPACKETCONN TEST"), addr); err != nil {
+                       if perr := parseWriteError(err); perr != nil {
+                               t.Error(perr)
+                       }
+                       t.Fatal(err)
+               }
+               if !reflect.DeepEqual(c2.LocalAddr(), addr) {
+                       t.Fatalf("got %#v; want %#v", c2.LocalAddr(), addr)
                }
        }
 }
index 5b24c7d09d1da9099c8bb8aced445e6c7e793325..9e581fcb419ad14b4f773206bf36fc5e1c8f5d10 100644 (file)
@@ -91,7 +91,7 @@ func fileListener(f *os.File) (Listener, error) {
        case *TCPAddr:
                return &TCPListener{fd}, nil
        case *UnixAddr:
-               return &UnixListener{fd, laddr.Name}, nil
+               return &UnixListener{fd: fd, path: laddr.Name, unlink: false}, nil
        }
        fd.Close()
        return nil, syscall.EINVAL
index 27958c7cc50b655fe2015006f70c149ddc834ac0..c4de1b6a9726fdfb7dc4e3baa29bbe3671589332 100644 (file)
@@ -9,7 +9,7 @@ import (
        "time"
 )
 
-const cacheMaxAge = 5 * time.Minute
+const cacheMaxAge = 5 * time.Second
 
 func parseLiteralIP(addr string) string {
        var ip IP
@@ -27,51 +27,76 @@ func parseLiteralIP(addr string) string {
        return ip.String() + "%" + zone
 }
 
-// Simple cache.
+// hosts contains known host entries.
 var hosts struct {
        sync.Mutex
+
+       // Key for the list of literal IP addresses must be a host
+       // name. It would be part of DNS labels, a FQDN or an absolute
+       // FQDN.
+       // For now the key is converted to lower case for convenience.
        byName map[string][]string
+
+       // Key for the list of host names must be a literal IP address
+       // including IPv6 address with zone identifier.
+       // We don't support old-classful IP address notation.
        byAddr map[string][]string
+
        expire time.Time
        path   string
+       mtime  time.Time
+       size   int64
 }
 
 func readHosts() {
        now := time.Now()
        hp := testHookHostsPath
-       if len(hosts.byName) == 0 || now.After(hosts.expire) || hosts.path != hp {
-               hs := make(map[string][]string)
-               is := make(map[string][]string)
-               var file *file
-               if file, _ = open(hp); file == nil {
-                       return
+
+       if now.Before(hosts.expire) && hosts.path == hp && len(hosts.byName) > 0 {
+               return
+       }
+       mtime, size, err := stat(hp)
+       if err == nil && hosts.path == hp && hosts.mtime.Equal(mtime) && hosts.size == size {
+               hosts.expire = now.Add(cacheMaxAge)
+               return
+       }
+
+       hs := make(map[string][]string)
+       is := make(map[string][]string)
+       var file *file
+       if file, _ = open(hp); file == nil {
+               return
+       }
+       for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+               if i := byteIndex(line, '#'); i >= 0 {
+                       // Discard comments.
+                       line = line[0:i]
                }
-               for line, ok := file.readLine(); ok; line, ok = file.readLine() {
-                       if i := byteIndex(line, '#'); i >= 0 {
-                               // Discard comments.
-                               line = line[0:i]
-                       }
-                       f := getFields(line)
-                       if len(f) < 2 {
-                               continue
-                       }
-                       addr := parseLiteralIP(f[0])
-                       if addr == "" {
-                               continue
-                       }
-                       for i := 1; i < len(f); i++ {
-                               h := f[i]
-                               hs[h] = append(hs[h], addr)
-                               is[addr] = append(is[addr], h)
-                       }
+               f := getFields(line)
+               if len(f) < 2 {
+                       continue
+               }
+               addr := parseLiteralIP(f[0])
+               if addr == "" {
+                       continue
+               }
+               for i := 1; i < len(f); i++ {
+                       name := absDomainName([]byte(f[i]))
+                       h := []byte(f[i])
+                       lowerASCIIBytes(h)
+                       key := absDomainName(h)
+                       hs[key] = append(hs[key], addr)
+                       is[addr] = append(is[addr], name)
                }
-               // Update the data cache.
-               hosts.expire = now.Add(cacheMaxAge)
-               hosts.path = hp
-               hosts.byName = hs
-               hosts.byAddr = is
-               file.close()
        }
+       // Update the data cache.
+       hosts.expire = now.Add(cacheMaxAge)
+       hosts.path = hp
+       hosts.byName = hs
+       hosts.byAddr = is
+       hosts.mtime = mtime
+       hosts.size = size
+       file.close()
 }
 
 // lookupStaticHost looks up the addresses for the given host from /etc/hosts.
@@ -80,7 +105,11 @@ func lookupStaticHost(host string) []string {
        defer hosts.Unlock()
        readHosts()
        if len(hosts.byName) != 0 {
-               if ips, ok := hosts.byName[host]; ok {
+               // TODO(jbd,bradfitz): avoid this alloc if host is already all lowercase?
+               // or linear scan the byName map if it's small enough?
+               lowerHost := []byte(host)
+               lowerASCIIBytes(lowerHost)
+               if ips, ok := hosts.byName[absDomainName(lowerHost)]; ok {
                        return ips
                }
        }
index aca64c38b05c25812856ed05545a2d46bfd18d98..4c67bfa9824eddad56618ace0937fbaeb2c0cfff 100644 (file)
@@ -6,6 +6,7 @@ package net
 
 import (
        "reflect"
+       "strings"
        "testing"
 )
 
@@ -48,6 +49,13 @@ var lookupStaticHostTests = []struct {
                        {"localhost.localdomain", []string{"fe80::3%lo0"}},
                },
        },
+       {
+               "testdata/case-hosts", // see golang.org/issue/12806
+               []staticHostEntry{
+                       {"PreserveMe", []string{"127.0.0.1", "::1"}},
+                       {"PreserveMe.local", []string{"127.0.0.1", "::1"}},
+               },
+       },
 }
 
 func TestLookupStaticHost(t *testing.T) {
@@ -56,9 +64,12 @@ func TestLookupStaticHost(t *testing.T) {
        for _, tt := range lookupStaticHostTests {
                testHookHostsPath = tt.name
                for _, ent := range tt.ents {
-                       addrs := lookupStaticHost(ent.in)
-                       if !reflect.DeepEqual(addrs, ent.out) {
-                               t.Errorf("%s, lookupStaticHost(%s) = %v; want %v", tt.name, ent.in, addrs, ent.out)
+                       ins := []string{ent.in, absDomainName([]byte(ent.in)), strings.ToLower(ent.in), strings.ToUpper(ent.in)}
+                       for _, in := range ins {
+                               addrs := lookupStaticHost(in)
+                               if !reflect.DeepEqual(addrs, ent.out) {
+                                       t.Errorf("%s, lookupStaticHost(%s) = %v; want %v", tt.name, in, addrs, ent.out)
+                               }
                        }
                }
        }
@@ -103,6 +114,13 @@ var lookupStaticAddrTests = []struct {
                        {"fe80::3%lo0", []string{"localhost", "localhost.localdomain"}},
                },
        },
+       {
+               "testdata/case-hosts", // see golang.org/issue/12806
+               []staticHostEntry{
+                       {"127.0.0.1", []string{"PreserveMe", "PreserveMe.local"}},
+                       {"::1", []string{"PreserveMe", "PreserveMe.local"}},
+               },
+       },
 }
 
 func TestLookupStaticAddr(t *testing.T) {
@@ -112,6 +130,9 @@ func TestLookupStaticAddr(t *testing.T) {
                testHookHostsPath = tt.name
                for _, ent := range tt.ents {
                        hosts := lookupStaticAddr(ent.in)
+                       for i := range ent.out {
+                               ent.out[i] = absDomainName([]byte(ent.out[i]))
+                       }
                        if !reflect.DeepEqual(hosts, ent.out) {
                                t.Errorf("%s, lookupStaticAddr(%s) = %v; want %v", tt.name, ent.in, hosts, ent.out)
                        }
index 4efbe7abeec001395c6cec764a081299b4a0031f..9b4d8754183247661e339a104bd6a1d2738323b2 100644 (file)
@@ -77,15 +77,15 @@ type Handler struct {
 //      Env: []string{"SCRIPT_FILENAME=foo.php"},
 //    }
 func removeLeadingDuplicates(env []string) (ret []string) {
-       n := len(env)
-       for i := 0; i < n; i++ {
-               e := env[i]
-               s := strings.SplitN(e, "=", 2)[0]
+       for i, e := range env {
                found := false
-               for j := i + 1; j < n; j++ {
-                       if s == strings.SplitN(env[j], "=", 2)[0] {
-                               found = true
-                               break
+               if eq := strings.IndexByte(e, '='); eq != -1 {
+                       keq := e[:eq+1] // "key="
+                       for _, e2 := range env[i+1:] {
+                               if strings.HasPrefix(e2, keq) {
+                                       found = true
+                                       break
+                               }
                        }
                }
                if !found {
@@ -159,10 +159,6 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
                env = append(env, "CONTENT_TYPE="+ctype)
        }
 
-       if h.Env != nil {
-               env = append(env, h.Env...)
-       }
-
        envPath := os.Getenv("PATH")
        if envPath == "" {
                envPath = "/bin:/usr/bin:/usr/ucb:/usr/bsd:/usr/local/bin"
@@ -181,6 +177,10 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
                }
        }
 
+       if h.Env != nil {
+               env = append(env, h.Env...)
+       }
+
        env = removeLeadingDuplicates(env)
 
        var cwd, path string
index f3411105ca9b01c7dc2bbecdd9f2605882e7499c..fb7d66adb9fd4ae063913e2bc6768bce3b64e7ab 100644 (file)
@@ -16,6 +16,7 @@ import (
        "os"
        "os/exec"
        "path/filepath"
+       "reflect"
        "runtime"
        "strconv"
        "strings"
@@ -488,12 +489,36 @@ func TestEnvOverride(t *testing.T) {
                Args: []string{cgifile},
                Env: []string{
                        "SCRIPT_FILENAME=" + cgifile,
-                       "REQUEST_URI=/foo/bar"},
+                       "REQUEST_URI=/foo/bar",
+                       "PATH=/wibble"},
        }
        expectedMap := map[string]string{
                "cwd": cwd,
                "env-SCRIPT_FILENAME": cgifile,
                "env-REQUEST_URI":     "/foo/bar",
+               "env-PATH":            "/wibble",
        }
        runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap)
 }
+
+func TestRemoveLeadingDuplicates(t *testing.T) {
+       tests := []struct {
+               env  []string
+               want []string
+       }{
+               {
+                       env:  []string{"a=b", "b=c", "a=b2"},
+                       want: []string{"b=c", "a=b2"},
+               },
+               {
+                       env:  []string{"a=b", "b=c", "d", "e=f"},
+                       want: []string{"a=b", "b=c", "d", "e=f"},
+               },
+       }
+       for _, tt := range tests {
+               got := removeLeadingDuplicates(tt.env)
+               if !reflect.DeepEqual(got, tt.want) {
+                       t.Errorf("removeLeadingDuplicates(%q) = %q; want %q", tt.env, got, tt.want)
+               }
+       }
+}
index 7f2fbb4678ef1c32164620d459b0599680952d91..3106d229da6f7c2c448c397980c540f5cf1315e1 100644 (file)
@@ -10,6 +10,7 @@
 package http
 
 import (
+       "crypto/tls"
        "encoding/base64"
        "errors"
        "fmt"
@@ -19,7 +20,6 @@ import (
        "net/url"
        "strings"
        "sync"
-       "sync/atomic"
        "time"
 )
 
@@ -65,10 +65,15 @@ type Client struct {
        //
        // 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.
+       // The Client cancels requests to the underlying Transport
+       // using the Request.Cancel mechanism. Requests passed
+       // to Client.Do may still set Request.Cancel; both will
+       // cancel the request.
+       //
+       // For compatibility, the Client will also use the deprecated
+       // CancelRequest method on Transport if found. New
+       // RoundTripper implementations should use Request.Cancel
+       // instead of implementing CancelRequest.
        Timeout time.Duration
 }
 
@@ -82,19 +87,26 @@ var DefaultClient = &Client{}
 // goroutines.
 type RoundTripper interface {
        // RoundTrip executes a single HTTP transaction, returning
-       // the Response for the request req.  RoundTrip should not
-       // attempt to interpret the response.  In particular,
-       // RoundTrip must return err == nil if it obtained a response,
-       // regardless of the response's HTTP status code.  A non-nil
-       // err should be reserved for failure to obtain a response.
-       // Similarly, RoundTrip should not attempt to handle
-       // higher-level protocol details such as redirects,
+       // a Response for the provided Request.
+       //
+       // RoundTrip should not attempt to interpret the response. In
+       // particular, RoundTrip must return err == nil if it obtained
+       // a response, regardless of the response's HTTP status code.
+       // A non-nil err should be reserved for failure to obtain a
+       // response. Similarly, RoundTrip should not attempt to
+       // handle higher-level protocol details such as redirects,
        // authentication, or cookies.
        //
        // RoundTrip should not modify the request, except for
-       // consuming and closing the Body, including on errors. The
-       // request's URL and Header fields are guaranteed to be
-       // initialized.
+       // consuming and closing the Request's Body.
+       //
+       // RoundTrip must always close the body, including on errors,
+       // but depending on the implementation may do so in a separate
+       // goroutine even after RoundTrip returns. This means that
+       // callers wanting to reuse the body for subsequent requests
+       // must arrange to wait for the Close call before doing so.
+       //
+       // The Request's URL and Header fields must be initialized.
        RoundTrip(*Request) (*Response, error)
 }
 
@@ -134,13 +146,13 @@ type readClose struct {
        io.Closer
 }
 
-func (c *Client) send(req *Request) (*Response, error) {
+func (c *Client) send(req *Request, deadline time.Time) (*Response, error) {
        if c.Jar != nil {
                for _, cookie := range c.Jar.Cookies(req.URL) {
                        req.AddCookie(cookie)
                }
        }
-       resp, err := send(req, c.transport())
+       resp, err := send(req, c.transport(), deadline)
        if err != nil {
                return nil, err
        }
@@ -171,13 +183,21 @@ func (c *Client) send(req *Request) (*Response, error) {
 //
 // 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" {
+       method := valueOrDefault(req.Method, "GET")
+       if method == "GET" || method == "HEAD" {
                return c.doFollowingRedirects(req, shouldRedirectGet)
        }
-       if req.Method == "POST" || req.Method == "PUT" {
+       if method == "POST" || method == "PUT" {
                return c.doFollowingRedirects(req, shouldRedirectPost)
        }
-       return c.send(req)
+       return c.send(req, c.deadline())
+}
+
+func (c *Client) deadline() time.Time {
+       if c.Timeout > 0 {
+               return time.Now().Add(c.Timeout)
+       }
+       return time.Time{}
 }
 
 func (c *Client) transport() RoundTripper {
@@ -189,8 +209,10 @@ func (c *Client) transport() RoundTripper {
 
 // 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 {
+func send(ireq *Request, rt RoundTripper, deadline time.Time) (*Response, error) {
+       req := ireq // req is either the original request, or a modified fork
+
+       if rt == nil {
                req.closeBody()
                return nil, errors.New("http: no Client.Transport or DefaultTransport")
        }
@@ -205,28 +227,122 @@ func send(req *Request, t RoundTripper) (resp *Response, err error) {
                return nil, errors.New("http: Request.RequestURI can't be set in client requests.")
        }
 
+       // forkReq forks req into a shallow clone of ireq the first
+       // time it's called.
+       forkReq := func() {
+               if ireq == req {
+                       req = new(Request)
+                       *req = *ireq // shallow clone
+               }
+       }
+
        // Most the callers of send (Get, Post, et al) don't need
        // Headers, leaving it uninitialized.  We guarantee to the
        // Transport that this has been initialized, though.
        if req.Header == nil {
+               forkReq()
                req.Header = make(Header)
        }
 
        if u := req.URL.User; u != nil && req.Header.Get("Authorization") == "" {
                username := u.Username()
                password, _ := u.Password()
+               forkReq()
+               req.Header = cloneHeader(ireq.Header)
                req.Header.Set("Authorization", "Basic "+basicAuth(username, password))
        }
-       resp, err = t.RoundTrip(req)
+
+       if !deadline.IsZero() {
+               forkReq()
+       }
+       stopTimer, wasCanceled := setRequestCancel(req, rt, deadline)
+
+       resp, err := rt.RoundTrip(req)
        if err != nil {
+               stopTimer()
                if resp != nil {
                        log.Printf("RoundTripper returned a response & error; ignoring response")
                }
+               if tlsErr, ok := err.(tls.RecordHeaderError); ok {
+                       // If we get a bad TLS record header, check to see if the
+                       // response looks like HTTP and give a more helpful error.
+                       // See golang.org/issue/11111.
+                       if string(tlsErr.RecordHeader[:]) == "HTTP/" {
+                               err = errors.New("http: server gave HTTP response to HTTPS client")
+                       }
+               }
                return nil, err
        }
+       if !deadline.IsZero() {
+               resp.Body = &cancelTimerBody{
+                       stop:           stopTimer,
+                       rc:             resp.Body,
+                       reqWasCanceled: wasCanceled,
+               }
+       }
        return resp, nil
 }
 
+// setRequestCancel sets the Cancel field of req, if deadline is
+// non-zero. The RoundTripper's type is used to determine whether the legacy
+// CancelRequest behavior should be used.
+func setRequestCancel(req *Request, rt RoundTripper, deadline time.Time) (stopTimer func(), wasCanceled func() bool) {
+       if deadline.IsZero() {
+               return nop, alwaysFalse
+       }
+
+       initialReqCancel := req.Cancel // the user's original Request.Cancel, if any
+
+       cancel := make(chan struct{})
+       req.Cancel = cancel
+
+       wasCanceled = func() bool {
+               select {
+               case <-cancel:
+                       return true
+               default:
+                       return false
+               }
+       }
+
+       doCancel := func() {
+               // The new way:
+               close(cancel)
+
+               // The legacy compatibility way, used only
+               // for RoundTripper implementations written
+               // before Go 1.5 or Go 1.6.
+               type canceler interface {
+                       CancelRequest(*Request)
+               }
+               switch v := rt.(type) {
+               case *Transport, *http2Transport:
+                       // Do nothing. The net/http package's transports
+                       // support the new Request.Cancel channel
+               case canceler:
+                       v.CancelRequest(req)
+               }
+       }
+
+       stopTimerCh := make(chan struct{})
+       var once sync.Once
+       stopTimer = func() { once.Do(func() { close(stopTimerCh) }) }
+
+       timer := time.NewTimer(deadline.Sub(time.Now()))
+       go func() {
+               select {
+               case <-initialReqCancel:
+                       doCancel()
+               case <-timer.C:
+                       doCancel()
+               case <-stopTimerCh:
+                       timer.Stop()
+               }
+       }()
+
+       return stopTimer, wasCanceled
+}
+
 // See 2 (end of page 4) http://www.ietf.org/rfc/rfc2617.txt
 // "To receive authorization, the client sends the userid and password,
 // separated by a single colon (":") character, within a base64
@@ -321,34 +437,15 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
                return nil, errors.New("http: nil Request.URL")
        }
 
-       var reqmu sync.Mutex // guards req
        req := ireq
-
-       var timer *time.Timer
-       var atomicWasCanceled int32 // atomic bool (1 or 0)
-       var wasCanceled = alwaysFalse
-       if c.Timeout > 0 {
-               wasCanceled = func() bool { return atomic.LoadInt32(&atomicWasCanceled) != 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() {
-                       atomic.StoreInt32(&atomicWasCanceled, 1)
-                       reqmu.Lock()
-                       defer reqmu.Unlock()
-                       tr.CancelRequest(req)
-               })
-       }
+       deadline := c.deadline()
 
        urlStr := "" // next relative or absolute URL to fetch (after first request)
        redirectFailed := false
        for redirect := 0; ; redirect++ {
                if redirect != 0 {
                        nreq := new(Request)
+                       nreq.Cancel = ireq.Cancel
                        nreq.Method = ireq.Method
                        if ireq.Method == "POST" || ireq.Method == "PUT" {
                                nreq.Method = "GET"
@@ -371,14 +468,12 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
                                        break
                                }
                        }
-                       reqmu.Lock()
                        req = nreq
-                       reqmu.Unlock()
                }
 
                urlStr = req.URL.String()
-               if resp, err = c.send(req); err != nil {
-                       if wasCanceled() {
+               if resp, err = c.send(req, deadline); err != nil {
+                       if !deadline.IsZero() && !time.Now().Before(deadline) {
                                err = &httpError{
                                        err:     err.Error() + " (Client.Timeout exceeded while awaiting headers)",
                                        timeout: true,
@@ -403,19 +498,12 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
                        via = append(via, req)
                        continue
                }
-               if timer != nil {
-                       resp.Body = &cancelTimerBody{
-                               t:              timer,
-                               rc:             resp.Body,
-                               reqWasCanceled: wasCanceled,
-                       }
-               }
                return resp, nil
        }
 
-       method := ireq.Method
+       method := valueOrDefault(ireq.Method, "GET")
        urlErr := &url.Error{
-               Op:  method[0:1] + strings.ToLower(method[1:]),
+               Op:  method[:1] + strings.ToLower(method[1:]),
                URL: urlStr,
                Err: err,
        }
@@ -528,30 +616,35 @@ func (c *Client) Head(url string) (resp *Response, err error) {
 }
 
 // cancelTimerBody is an io.ReadCloser that wraps rc with two features:
-// 1) on Read EOF or Close, the timer t is Stopped,
+// 1) on Read error or close, the stop func is called.
 // 2) On Read failure, if reqWasCanceled is true, the error is wrapped and
 //    marked as net.Error that hit its timeout.
 type cancelTimerBody struct {
-       t              *time.Timer
+       stop           func() // stops the time.Timer waiting to cancel the request
        rc             io.ReadCloser
        reqWasCanceled func() bool
 }
 
 func (b *cancelTimerBody) Read(p []byte) (n int, err error) {
        n, err = b.rc.Read(p)
+       if err == nil {
+               return n, nil
+       }
+       b.stop()
        if err == io.EOF {
-               b.t.Stop()
-       } else if err != nil && b.reqWasCanceled() {
-               return n, &httpError{
+               return n, err
+       }
+       if b.reqWasCanceled() {
+               err = &httpError{
                        err:     err.Error() + " (Client.Timeout exceeded while reading body)",
                        timeout: true,
                }
        }
-       return
+       return n, err
 }
 
 func (b *cancelTimerBody) Close() error {
        err := b.rc.Close()
-       b.t.Stop()
+       b.stop()
        return err
 }
index 7b524d381bce9a5e2acc06b1f2cc1e437de26bb9..8939dc8baf9cc9ac4e95784fac3ca897543c5f4b 100644 (file)
@@ -20,8 +20,6 @@ import (
        . "net/http"
        "net/http/httptest"
        "net/url"
-       "reflect"
-       "sort"
        "strconv"
        "strings"
        "sync"
@@ -83,12 +81,15 @@ func TestClient(t *testing.T) {
        }
 }
 
-func TestClientHead(t *testing.T) {
+func TestClientHead_h1(t *testing.T) { testClientHead(t, h1Mode) }
+func TestClientHead_h2(t *testing.T) { testClientHead(t, h2Mode) }
+
+func testClientHead(t *testing.T, h2 bool) {
        defer afterTest(t)
-       ts := httptest.NewServer(robotsTxtHandler)
-       defer ts.Close()
+       cst := newClientServerTest(t, h2, robotsTxtHandler)
+       defer cst.close()
 
-       r, err := Head(ts.URL)
+       r, err := cst.c.Head(cst.ts.URL)
        if err != nil {
                t.Fatal(err)
        }
@@ -230,9 +231,18 @@ func TestClientRedirects(t *testing.T) {
                t.Errorf("with default client Do, expected error %q, got %q", e, g)
        }
 
+       // Requests with an empty Method should also redirect (Issue 12705)
+       greq.Method = ""
+       _, err = c.Do(greq)
+       if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
+               t.Errorf("with default client Do and empty Method, expected error %q, got %q", e, g)
+       }
+
        var checkErr error
        var lastVia []*Request
-       c = &Client{CheckRedirect: func(_ *Request, via []*Request) error {
+       var lastReq *Request
+       c = &Client{CheckRedirect: func(req *Request, via []*Request) error {
+               lastReq = req
                lastVia = via
                return checkErr
        }}
@@ -252,6 +262,20 @@ func TestClientRedirects(t *testing.T) {
                t.Errorf("expected lastVia to have contained %d elements; got %d", e, g)
        }
 
+       // Test that Request.Cancel is propagated between requests (Issue 14053)
+       creq, _ := NewRequest("HEAD", ts.URL, nil)
+       cancel := make(chan struct{})
+       creq.Cancel = cancel
+       if _, err := c.Do(creq); err != nil {
+               t.Fatal(err)
+       }
+       if lastReq == nil {
+               t.Fatal("didn't see redirect")
+       }
+       if lastReq.Cancel != cancel {
+               t.Errorf("expected lastReq to have the cancel channel set on the inital req")
+       }
+
        checkErr = errors.New("no redirects allowed")
        res, err = c.Get(ts.URL)
        if urlError, ok := err.(*url.Error); !ok || urlError.Err != checkErr {
@@ -486,20 +510,23 @@ func (j *RecordingJar) logf(format string, args ...interface{}) {
        fmt.Fprintf(&j.log, format, args...)
 }
 
-func TestStreamingGet(t *testing.T) {
+func TestStreamingGet_h1(t *testing.T) { testStreamingGet(t, h1Mode) }
+func TestStreamingGet_h2(t *testing.T) { testStreamingGet(t, h2Mode) }
+
+func testStreamingGet(t *testing.T, h2 bool) {
        defer afterTest(t)
        say := make(chan string)
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
                w.(Flusher).Flush()
                for str := range say {
                        w.Write([]byte(str))
                        w.(Flusher).Flush()
                }
        }))
-       defer ts.Close()
+       defer cst.close()
 
-       c := &Client{}
-       res, err := c.Get(ts.URL)
+       c := cst.c
+       res, err := c.Get(cst.ts.URL)
        if err != nil {
                t.Fatal(err)
        }
@@ -642,14 +669,18 @@ func newTLSTransport(t *testing.T, ts *httptest.Server) *Transport {
 
 func TestClientWithCorrectTLSServerName(t *testing.T) {
        defer afterTest(t)
+
+       const serverName = "example.com"
        ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-               if r.TLS.ServerName != "127.0.0.1" {
-                       t.Errorf("expected client to set ServerName 127.0.0.1, got: %q", r.TLS.ServerName)
+               if r.TLS.ServerName != serverName {
+                       t.Errorf("expected client to set ServerName %q, got: %q", serverName, r.TLS.ServerName)
                }
        }))
        defer ts.Close()
 
-       c := &Client{Transport: newTLSTransport(t, ts)}
+       trans := newTLSTransport(t, ts)
+       trans.TLSClientConfig.ServerName = serverName
+       c := &Client{Transport: trans}
        if _, err := c.Get(ts.URL); err != nil {
                t.Fatalf("expected successful TLS connection, got error: %v", err)
        }
@@ -739,15 +770,37 @@ func TestResponseSetsTLSConnectionState(t *testing.T) {
        }
 }
 
+// Check that an HTTPS client can interpret a particular TLS error
+// to determine that the server is speaking HTTP.
+// See golang.org/issue/11111.
+func TestHTTPSClientDetectsHTTPServer(t *testing.T) {
+       defer afterTest(t)
+       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
+       defer ts.Close()
+
+       _, err := Get(strings.Replace(ts.URL, "http", "https", 1))
+       if got := err.Error(); !strings.Contains(got, "HTTP response to HTTPS client") {
+               t.Fatalf("error = %q; want error indicating HTTP response to HTTPS request", got)
+       }
+}
+
 // Verify Response.ContentLength is populated. https://golang.org/issue/4126
-func TestClientHeadContentLength(t *testing.T) {
+func TestClientHeadContentLength_h1(t *testing.T) {
+       testClientHeadContentLength(t, h1Mode)
+}
+
+func TestClientHeadContentLength_h2(t *testing.T) {
+       testClientHeadContentLength(t, h2Mode)
+}
+
+func testClientHeadContentLength(t *testing.T, h2 bool) {
        defer afterTest(t)
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
                if v := r.FormValue("cl"); v != "" {
                        w.Header().Set("Content-Length", v)
                }
        }))
-       defer ts.Close()
+       defer cst.close()
        tests := []struct {
                suffix string
                want   int64
@@ -757,8 +810,8 @@ func TestClientHeadContentLength(t *testing.T) {
                {"", -1},
        }
        for _, tt := range tests {
-               req, _ := NewRequest("HEAD", ts.URL+tt.suffix, nil)
-               res, err := DefaultClient.Do(req)
+               req, _ := NewRequest("HEAD", cst.ts.URL+tt.suffix, nil)
+               res, err := cst.c.Do(req)
                if err != nil {
                        t.Fatal(err)
                }
@@ -884,14 +937,17 @@ func TestBasicAuthHeadersPreserved(t *testing.T) {
 
 }
 
-func TestClientTimeout(t *testing.T) {
+func TestClientTimeout_h1(t *testing.T) { testClientTimeout(t, h1Mode) }
+func TestClientTimeout_h2(t *testing.T) { testClientTimeout(t, h2Mode) }
+
+func testClientTimeout(t *testing.T, h2 bool) {
        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) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
                if r.URL.Path == "/" {
                        sawRoot <- true
                        Redirect(w, r, "/slow", StatusFound)
@@ -905,13 +961,11 @@ func TestClientTimeout(t *testing.T) {
                        return
                }
        }))
-       defer ts.Close()
+       defer cst.close()
        const timeout = 500 * time.Millisecond
-       c := &Client{
-               Timeout: timeout,
-       }
+       cst.c.Timeout = timeout
 
-       res, err := c.Get(ts.URL)
+       res, err := cst.c.Get(cst.ts.URL)
        if err != nil {
                t.Fatal(err)
        }
@@ -957,17 +1011,20 @@ func TestClientTimeout(t *testing.T) {
        }
 }
 
+func TestClientTimeout_Headers_h1(t *testing.T) { testClientTimeout_Headers(t, h1Mode) }
+func TestClientTimeout_Headers_h2(t *testing.T) { testClientTimeout_Headers(t, h2Mode) }
+
 // Client.Timeout firing before getting to the body
-func TestClientTimeout_Headers(t *testing.T) {
+func testClientTimeout_Headers(t *testing.T, h2 bool) {
        if testing.Short() {
                t.Skip("skipping in short mode")
        }
        defer afterTest(t)
        donec := make(chan bool)
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
                <-donec
        }))
-       defer ts.Close()
+       defer cst.close()
        // Note that we use a channel send here and not a close.
        // The race detector doesn't know that we're waiting for a timeout
        // and thinks that the waitgroup inside httptest.Server is added to concurrently
@@ -977,19 +1034,17 @@ func TestClientTimeout_Headers(t *testing.T) {
        // doesn't know this, so synchronize explicitly.
        defer func() { donec <- true }()
 
-       c := &Client{Timeout: 500 * time.Millisecond}
-
-       _, err := c.Get(ts.URL)
+       cst.c.Timeout = 500 * time.Millisecond
+       _, err := cst.c.Get(cst.ts.URL)
        if err == nil {
                t.Fatal("got response from Get; expected error")
        }
-       ue, ok := err.(*url.Error)
-       if !ok {
+       if _, ok := err.(*url.Error); !ok {
                t.Fatalf("Got error of type %T; want *url.Error", err)
        }
-       ne, ok := ue.Err.(net.Error)
+       ne, ok := err.(net.Error)
        if !ok {
-               t.Fatalf("Got url.Error.Err of type %T; want some net.Error", err)
+               t.Fatalf("Got error of type %T; want some net.Error", err)
        }
        if !ne.Timeout() {
                t.Error("net.Error.Timeout = false; want true")
@@ -999,18 +1054,20 @@ func TestClientTimeout_Headers(t *testing.T) {
        }
 }
 
-func TestClientRedirectEatsBody(t *testing.T) {
+func TestClientRedirectEatsBody_h1(t *testing.T) { testClientRedirectEatsBody(t, h1Mode) }
+func TestClientRedirectEatsBody_h2(t *testing.T) { testClientRedirectEatsBody(t, h2Mode) }
+func testClientRedirectEatsBody(t *testing.T, h2 bool) {
        defer afterTest(t)
        saw := make(chan string, 2)
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+       cst := newClientServerTest(t, h2, 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()
+       defer cst.close()
 
-       res, err := Get(ts.URL)
+       res, err := cst.c.Get(cst.ts.URL)
        if err != nil {
                t.Fatal(err)
        }
@@ -1047,76 +1104,6 @@ func (f eofReaderFunc) Read(p []byte) (n int, err error) {
        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"))
-               }
-
-               // How handlers set Trailers: declare it ahead of time
-               // with the Trailer header, and then mutate the
-               // Header() of those values later, after the response
-               // has been written (we wrote to w above).
-               w.Header().Set("Server-Trailer-A", "valuea")
-               w.Header().Set("Server-Trailer-C", "valuec") // skipping B
-       }))
-       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)
-       }
-}
-
 func TestReferer(t *testing.T) {
        tests := []struct {
                lastReq, newReq string // from -> to URLs
diff --git a/libgo/go/net/http/clientserver_test.go b/libgo/go/net/http/clientserver_test.go
new file mode 100644 (file)
index 0000000..3c87fd0
--- /dev/null
@@ -0,0 +1,1056 @@
+// Copyright 2015 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.
+
+// Tests that use both the client & server, in both HTTP/1 and HTTP/2 mode.
+
+package http_test
+
+import (
+       "bytes"
+       "compress/gzip"
+       "crypto/tls"
+       "fmt"
+       "io"
+       "io/ioutil"
+       "log"
+       "net"
+       . "net/http"
+       "net/http/httptest"
+       "net/url"
+       "os"
+       "reflect"
+       "runtime"
+       "sort"
+       "strings"
+       "sync"
+       "sync/atomic"
+       "testing"
+       "time"
+)
+
+type clientServerTest struct {
+       t  *testing.T
+       h2 bool
+       h  Handler
+       ts *httptest.Server
+       tr *Transport
+       c  *Client
+}
+
+func (t *clientServerTest) close() {
+       t.tr.CloseIdleConnections()
+       t.ts.Close()
+}
+
+const (
+       h1Mode = false
+       h2Mode = true
+)
+
+func newClientServerTest(t *testing.T, h2 bool, h Handler, opts ...interface{}) *clientServerTest {
+       cst := &clientServerTest{
+               t:  t,
+               h2: h2,
+               h:  h,
+               tr: &Transport{},
+       }
+       cst.c = &Client{Transport: cst.tr}
+
+       for _, opt := range opts {
+               switch opt := opt.(type) {
+               case func(*Transport):
+                       opt(cst.tr)
+               default:
+                       t.Fatalf("unhandled option type %T", opt)
+               }
+       }
+
+       if !h2 {
+               cst.ts = httptest.NewServer(h)
+               return cst
+       }
+       cst.ts = httptest.NewUnstartedServer(h)
+       ExportHttp2ConfigureServer(cst.ts.Config, nil)
+       cst.ts.TLS = cst.ts.Config.TLSConfig
+       cst.ts.StartTLS()
+
+       cst.tr.TLSClientConfig = &tls.Config{
+               InsecureSkipVerify: true,
+       }
+       if err := ExportHttp2ConfigureTransport(cst.tr); err != nil {
+               t.Fatal(err)
+       }
+       return cst
+}
+
+// Testing the newClientServerTest helper itself.
+func TestNewClientServerTest(t *testing.T) {
+       var got struct {
+               sync.Mutex
+               log []string
+       }
+       h := HandlerFunc(func(w ResponseWriter, r *Request) {
+               got.Lock()
+               defer got.Unlock()
+               got.log = append(got.log, r.Proto)
+       })
+       for _, v := range [2]bool{false, true} {
+               cst := newClientServerTest(t, v, h)
+               if _, err := cst.c.Head(cst.ts.URL); err != nil {
+                       t.Fatal(err)
+               }
+               cst.close()
+       }
+       got.Lock() // no need to unlock
+       if want := []string{"HTTP/1.1", "HTTP/2.0"}; !reflect.DeepEqual(got.log, want) {
+               t.Errorf("got %q; want %q", got.log, want)
+       }
+}
+
+func TestChunkedResponseHeaders_h1(t *testing.T) { testChunkedResponseHeaders(t, h1Mode) }
+func TestChunkedResponseHeaders_h2(t *testing.T) { testChunkedResponseHeaders(t, h2Mode) }
+
+func testChunkedResponseHeaders(t *testing.T, h2 bool) {
+       defer afterTest(t)
+       log.SetOutput(ioutil.Discard) // is noisy otherwise
+       defer log.SetOutput(os.Stderr)
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+               w.Header().Set("Content-Length", "intentional gibberish") // we check that this is deleted
+               w.(Flusher).Flush()
+               fmt.Fprintf(w, "I am a chunked response.")
+       }))
+       defer cst.close()
+
+       res, err := cst.c.Get(cst.ts.URL)
+       if err != nil {
+               t.Fatalf("Get error: %v", err)
+       }
+       defer res.Body.Close()
+       if g, e := res.ContentLength, int64(-1); g != e {
+               t.Errorf("expected ContentLength of %d; got %d", e, g)
+       }
+       wantTE := []string{"chunked"}
+       if h2 {
+               wantTE = nil
+       }
+       if !reflect.DeepEqual(res.TransferEncoding, wantTE) {
+               t.Errorf("TransferEncoding = %v; want %v", res.TransferEncoding, wantTE)
+       }
+       if got, haveCL := res.Header["Content-Length"]; haveCL {
+               t.Errorf("Unexpected Content-Length: %q", got)
+       }
+}
+
+type reqFunc func(c *Client, url string) (*Response, error)
+
+// h12Compare is a test that compares HTTP/1 and HTTP/2 behavior
+// against each other.
+type h12Compare struct {
+       Handler       func(ResponseWriter, *Request)    // required
+       ReqFunc       reqFunc                           // optional
+       CheckResponse func(proto string, res *Response) // optional
+       Opts          []interface{}
+}
+
+func (tt h12Compare) reqFunc() reqFunc {
+       if tt.ReqFunc == nil {
+               return (*Client).Get
+       }
+       return tt.ReqFunc
+}
+
+func (tt h12Compare) run(t *testing.T) {
+       cst1 := newClientServerTest(t, false, HandlerFunc(tt.Handler), tt.Opts...)
+       defer cst1.close()
+       cst2 := newClientServerTest(t, true, HandlerFunc(tt.Handler), tt.Opts...)
+       defer cst2.close()
+
+       res1, err := tt.reqFunc()(cst1.c, cst1.ts.URL)
+       if err != nil {
+               t.Errorf("HTTP/1 request: %v", err)
+               return
+       }
+       res2, err := tt.reqFunc()(cst2.c, cst2.ts.URL)
+       if err != nil {
+               t.Errorf("HTTP/2 request: %v", err)
+               return
+       }
+       tt.normalizeRes(t, res1, "HTTP/1.1")
+       tt.normalizeRes(t, res2, "HTTP/2.0")
+       res1body, res2body := res1.Body, res2.Body
+
+       eres1 := mostlyCopy(res1)
+       eres2 := mostlyCopy(res2)
+       if !reflect.DeepEqual(eres1, eres2) {
+               t.Errorf("Response headers to handler differed:\nhttp/1 (%v):\n\t%#v\nhttp/2 (%v):\n\t%#v",
+                       cst1.ts.URL, eres1, cst2.ts.URL, eres2)
+       }
+       if !reflect.DeepEqual(res1body, res2body) {
+               t.Errorf("Response bodies to handler differed.\nhttp1: %v\nhttp2: %v\n", res1body, res2body)
+       }
+       if fn := tt.CheckResponse; fn != nil {
+               res1.Body, res2.Body = res1body, res2body
+               fn("HTTP/1.1", res1)
+               fn("HTTP/2.0", res2)
+       }
+}
+
+func mostlyCopy(r *Response) *Response {
+       c := *r
+       c.Body = nil
+       c.TransferEncoding = nil
+       c.TLS = nil
+       c.Request = nil
+       return &c
+}
+
+type slurpResult struct {
+       io.ReadCloser
+       body []byte
+       err  error
+}
+
+func (sr slurpResult) String() string { return fmt.Sprintf("body %q; err %v", sr.body, sr.err) }
+
+func (tt h12Compare) normalizeRes(t *testing.T, res *Response, wantProto string) {
+       if res.Proto == wantProto {
+               res.Proto, res.ProtoMajor, res.ProtoMinor = "", 0, 0
+       } else {
+               t.Errorf("got %q response; want %q", res.Proto, wantProto)
+       }
+       slurp, err := ioutil.ReadAll(res.Body)
+       res.Body.Close()
+       res.Body = slurpResult{
+               ReadCloser: ioutil.NopCloser(bytes.NewReader(slurp)),
+               body:       slurp,
+               err:        err,
+       }
+       for i, v := range res.Header["Date"] {
+               res.Header["Date"][i] = strings.Repeat("x", len(v))
+       }
+       if res.Request == nil {
+               t.Errorf("for %s, no request", wantProto)
+       }
+       if (res.TLS != nil) != (wantProto == "HTTP/2.0") {
+               t.Errorf("TLS set = %v; want %v", res.TLS != nil, res.TLS == nil)
+       }
+}
+
+// Issue 13532
+func TestH12_HeadContentLengthNoBody(t *testing.T) {
+       h12Compare{
+               ReqFunc: (*Client).Head,
+               Handler: func(w ResponseWriter, r *Request) {
+               },
+       }.run(t)
+}
+
+func TestH12_HeadContentLengthSmallBody(t *testing.T) {
+       h12Compare{
+               ReqFunc: (*Client).Head,
+               Handler: func(w ResponseWriter, r *Request) {
+                       io.WriteString(w, "small")
+               },
+       }.run(t)
+}
+
+func TestH12_HeadContentLengthLargeBody(t *testing.T) {
+       h12Compare{
+               ReqFunc: (*Client).Head,
+               Handler: func(w ResponseWriter, r *Request) {
+                       chunk := strings.Repeat("x", 512<<10)
+                       for i := 0; i < 10; i++ {
+                               io.WriteString(w, chunk)
+                       }
+               },
+       }.run(t)
+}
+
+func TestH12_200NoBody(t *testing.T) {
+       h12Compare{Handler: func(w ResponseWriter, r *Request) {}}.run(t)
+}
+
+func TestH2_204NoBody(t *testing.T) { testH12_noBody(t, 204) }
+func TestH2_304NoBody(t *testing.T) { testH12_noBody(t, 304) }
+func TestH2_404NoBody(t *testing.T) { testH12_noBody(t, 404) }
+
+func testH12_noBody(t *testing.T, status int) {
+       h12Compare{Handler: func(w ResponseWriter, r *Request) {
+               w.WriteHeader(status)
+       }}.run(t)
+}
+
+func TestH12_SmallBody(t *testing.T) {
+       h12Compare{Handler: func(w ResponseWriter, r *Request) {
+               io.WriteString(w, "small body")
+       }}.run(t)
+}
+
+func TestH12_ExplicitContentLength(t *testing.T) {
+       h12Compare{Handler: func(w ResponseWriter, r *Request) {
+               w.Header().Set("Content-Length", "3")
+               io.WriteString(w, "foo")
+       }}.run(t)
+}
+
+func TestH12_FlushBeforeBody(t *testing.T) {
+       h12Compare{Handler: func(w ResponseWriter, r *Request) {
+               w.(Flusher).Flush()
+               io.WriteString(w, "foo")
+       }}.run(t)
+}
+
+func TestH12_FlushMidBody(t *testing.T) {
+       h12Compare{Handler: func(w ResponseWriter, r *Request) {
+               io.WriteString(w, "foo")
+               w.(Flusher).Flush()
+               io.WriteString(w, "bar")
+       }}.run(t)
+}
+
+func TestH12_Head_ExplicitLen(t *testing.T) {
+       h12Compare{
+               ReqFunc: (*Client).Head,
+               Handler: func(w ResponseWriter, r *Request) {
+                       if r.Method != "HEAD" {
+                               t.Errorf("unexpected method %q", r.Method)
+                       }
+                       w.Header().Set("Content-Length", "1235")
+               },
+       }.run(t)
+}
+
+func TestH12_Head_ImplicitLen(t *testing.T) {
+       h12Compare{
+               ReqFunc: (*Client).Head,
+               Handler: func(w ResponseWriter, r *Request) {
+                       if r.Method != "HEAD" {
+                               t.Errorf("unexpected method %q", r.Method)
+                       }
+                       io.WriteString(w, "foo")
+               },
+       }.run(t)
+}
+
+func TestH12_HandlerWritesTooLittle(t *testing.T) {
+       h12Compare{
+               Handler: func(w ResponseWriter, r *Request) {
+                       w.Header().Set("Content-Length", "3")
+                       io.WriteString(w, "12") // one byte short
+               },
+               CheckResponse: func(proto string, res *Response) {
+                       sr, ok := res.Body.(slurpResult)
+                       if !ok {
+                               t.Errorf("%s body is %T; want slurpResult", proto, res.Body)
+                               return
+                       }
+                       if sr.err != io.ErrUnexpectedEOF {
+                               t.Errorf("%s read error = %v; want io.ErrUnexpectedEOF", proto, sr.err)
+                       }
+                       if string(sr.body) != "12" {
+                               t.Errorf("%s body = %q; want %q", proto, sr.body, "12")
+                       }
+               },
+       }.run(t)
+}
+
+// Tests that the HTTP/1 and HTTP/2 servers prevent handlers from
+// writing more than they declared.  This test does not test whether
+// the transport deals with too much data, though, since the server
+// doesn't make it possible to send bogus data. For those tests, see
+// transport_test.go (for HTTP/1) or x/net/http2/transport_test.go
+// (for HTTP/2).
+func TestH12_HandlerWritesTooMuch(t *testing.T) {
+       h12Compare{
+               Handler: func(w ResponseWriter, r *Request) {
+                       w.Header().Set("Content-Length", "3")
+                       w.(Flusher).Flush()
+                       io.WriteString(w, "123")
+                       w.(Flusher).Flush()
+                       n, err := io.WriteString(w, "x") // too many
+                       if n > 0 || err == nil {
+                               t.Errorf("for proto %q, final write = %v, %v; want 0, some error", r.Proto, n, err)
+                       }
+               },
+       }.run(t)
+}
+
+// Verify that both our HTTP/1 and HTTP/2 request and auto-decompress gzip.
+// Some hosts send gzip even if you don't ask for it; see golang.org/issue/13298
+func TestH12_AutoGzip(t *testing.T) {
+       h12Compare{
+               Handler: func(w ResponseWriter, r *Request) {
+                       if ae := r.Header.Get("Accept-Encoding"); ae != "gzip" {
+                               t.Errorf("%s Accept-Encoding = %q; want gzip", r.Proto, ae)
+                       }
+                       w.Header().Set("Content-Encoding", "gzip")
+                       gz := gzip.NewWriter(w)
+                       io.WriteString(gz, "I am some gzipped content. Go go go go go go go go go go go go should compress well.")
+                       gz.Close()
+               },
+       }.run(t)
+}
+
+func TestH12_AutoGzip_Disabled(t *testing.T) {
+       h12Compare{
+               Opts: []interface{}{
+                       func(tr *Transport) { tr.DisableCompression = true },
+               },
+               Handler: func(w ResponseWriter, r *Request) {
+                       fmt.Fprintf(w, "%q", r.Header["Accept-Encoding"])
+                       if ae := r.Header.Get("Accept-Encoding"); ae != "" {
+                               t.Errorf("%s Accept-Encoding = %q; want empty", r.Proto, ae)
+                       }
+               },
+       }.run(t)
+}
+
+// Test304Responses verifies that 304s don't declare that they're
+// chunking in their response headers and aren't allowed to produce
+// output.
+func Test304Responses_h1(t *testing.T) { test304Responses(t, h1Mode) }
+func Test304Responses_h2(t *testing.T) { test304Responses(t, h2Mode) }
+
+func test304Responses(t *testing.T, h2 bool) {
+       defer afterTest(t)
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+               w.WriteHeader(StatusNotModified)
+               _, err := w.Write([]byte("illegal body"))
+               if err != ErrBodyNotAllowed {
+                       t.Errorf("on Write, expected ErrBodyNotAllowed, got %v", err)
+               }
+       }))
+       defer cst.close()
+       res, err := cst.c.Get(cst.ts.URL)
+       if err != nil {
+               t.Fatal(err)
+       }
+       if len(res.TransferEncoding) > 0 {
+               t.Errorf("expected no TransferEncoding; got %v", res.TransferEncoding)
+       }
+       body, err := ioutil.ReadAll(res.Body)
+       if err != nil {
+               t.Error(err)
+       }
+       if len(body) > 0 {
+               t.Errorf("got unexpected body %q", string(body))
+       }
+}
+
+func TestH12_ServerEmptyContentLength(t *testing.T) {
+       h12Compare{
+               Handler: func(w ResponseWriter, r *Request) {
+                       w.Header()["Content-Type"] = []string{""}
+                       io.WriteString(w, "<html><body>hi</body></html>")
+               },
+       }.run(t)
+}
+
+func TestH12_RequestContentLength_Known_NonZero(t *testing.T) {
+       h12requestContentLength(t, func() io.Reader { return strings.NewReader("FOUR") }, 4)
+}
+
+func TestH12_RequestContentLength_Known_Zero(t *testing.T) {
+       h12requestContentLength(t, func() io.Reader { return strings.NewReader("") }, 0)
+}
+
+func TestH12_RequestContentLength_Unknown(t *testing.T) {
+       h12requestContentLength(t, func() io.Reader { return struct{ io.Reader }{strings.NewReader("Stuff")} }, -1)
+}
+
+func h12requestContentLength(t *testing.T, bodyfn func() io.Reader, wantLen int64) {
+       h12Compare{
+               Handler: func(w ResponseWriter, r *Request) {
+                       w.Header().Set("Got-Length", fmt.Sprint(r.ContentLength))
+                       fmt.Fprintf(w, "Req.ContentLength=%v", r.ContentLength)
+               },
+               ReqFunc: func(c *Client, url string) (*Response, error) {
+                       return c.Post(url, "text/plain", bodyfn())
+               },
+               CheckResponse: func(proto string, res *Response) {
+                       if got, want := res.Header.Get("Got-Length"), fmt.Sprint(wantLen); got != want {
+                               t.Errorf("Proto %q got length %q; want %q", proto, got, want)
+                       }
+               },
+       }.run(t)
+}
+
+// Tests that closing the Request.Cancel channel also while still
+// reading the response body. Issue 13159.
+func TestCancelRequestMidBody_h1(t *testing.T) { testCancelRequestMidBody(t, h1Mode) }
+func TestCancelRequestMidBody_h2(t *testing.T) { testCancelRequestMidBody(t, h2Mode) }
+func testCancelRequestMidBody(t *testing.T, h2 bool) {
+       defer afterTest(t)
+       unblock := make(chan bool)
+       didFlush := make(chan bool, 1)
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+               io.WriteString(w, "Hello")
+               w.(Flusher).Flush()
+               didFlush <- true
+               <-unblock
+               io.WriteString(w, ", world.")
+       }))
+       defer cst.close()
+       defer close(unblock)
+
+       req, _ := NewRequest("GET", cst.ts.URL, nil)
+       cancel := make(chan struct{})
+       req.Cancel = cancel
+
+       res, err := cst.c.Do(req)
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer res.Body.Close()
+       <-didFlush
+
+       // Read a bit before we cancel. (Issue 13626)
+       // We should have "Hello" at least sitting there.
+       firstRead := make([]byte, 10)
+       n, err := res.Body.Read(firstRead)
+       if err != nil {
+               t.Fatal(err)
+       }
+       firstRead = firstRead[:n]
+
+       close(cancel)
+
+       rest, err := ioutil.ReadAll(res.Body)
+       all := string(firstRead) + string(rest)
+       if all != "Hello" {
+               t.Errorf("Read %q (%q + %q); want Hello", all, firstRead, rest)
+       }
+       if !reflect.DeepEqual(err, ExportErrRequestCanceled) {
+               t.Errorf("ReadAll error = %v; want %v", err, ExportErrRequestCanceled)
+       }
+}
+
+// Tests that clients can send trailers to a server and that the server can read them.
+func TestTrailersClientToServer_h1(t *testing.T) { testTrailersClientToServer(t, h1Mode) }
+func TestTrailersClientToServer_h2(t *testing.T) { testTrailersClientToServer(t, h2Mode) }
+
+func testTrailersClientToServer(t *testing.T, h2 bool) {
+       defer afterTest(t)
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+               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"))
+               }
+       }))
+       defer cst.close()
+
+       var req *Request
+       req, _ = NewRequest("POST", cst.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 := cst.c.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)
+       }
+}
+
+// Tests that servers send trailers to a client and that the client can read them.
+func TestTrailersServerToClient_h1(t *testing.T)       { testTrailersServerToClient(t, h1Mode, false) }
+func TestTrailersServerToClient_h2(t *testing.T)       { testTrailersServerToClient(t, h2Mode, false) }
+func TestTrailersServerToClient_Flush_h1(t *testing.T) { testTrailersServerToClient(t, h1Mode, true) }
+func TestTrailersServerToClient_Flush_h2(t *testing.T) { testTrailersServerToClient(t, h2Mode, true) }
+
+func testTrailersServerToClient(t *testing.T, h2, flush bool) {
+       defer afterTest(t)
+       const body = "Some body"
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+               w.Header().Set("Trailer", "Server-Trailer-A, Server-Trailer-B")
+               w.Header().Add("Trailer", "Server-Trailer-C")
+
+               io.WriteString(w, body)
+               if flush {
+                       w.(Flusher).Flush()
+               }
+
+               // How handlers set Trailers: declare it ahead of time
+               // with the Trailer header, and then mutate the
+               // Header() of those values later, after the response
+               // has been written (we wrote to w above).
+               w.Header().Set("Server-Trailer-A", "valuea")
+               w.Header().Set("Server-Trailer-C", "valuec") // skipping B
+               w.Header().Set("Server-Trailer-NotDeclared", "should be omitted")
+       }))
+       defer cst.close()
+
+       res, err := cst.c.Get(cst.ts.URL)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       wantHeader := Header{
+               "Content-Type": {"text/plain; charset=utf-8"},
+       }
+       wantLen := -1
+       if h2 && !flush {
+               // In HTTP/1.1, any use of trailers forces HTTP/1.1
+               // chunking and a flush at the first write. That's
+               // unnecessary with HTTP/2's framing, so the server
+               // is able to calculate the length while still sending
+               // trailers afterwards.
+               wantLen = len(body)
+               wantHeader["Content-Length"] = []string{fmt.Sprint(wantLen)}
+       }
+       if res.ContentLength != int64(wantLen) {
+               t.Errorf("ContentLength = %v; want %v", res.ContentLength, wantLen)
+       }
+
+       delete(res.Header, "Date") // irrelevant for test
+       if !reflect.DeepEqual(res.Header, wantHeader) {
+               t.Errorf("Header = %v; want %v", res.Header, wantHeader)
+       }
+
+       if got, want := res.Trailer, (Header{
+               "Server-Trailer-A": nil,
+               "Server-Trailer-B": nil,
+               "Server-Trailer-C": nil,
+       }); !reflect.DeepEqual(got, want) {
+               t.Errorf("Trailer before body read = %v; want %v", got, want)
+       }
+
+       if err := wantBody(res, nil, body); err != nil {
+               t.Fatal(err)
+       }
+
+       if got, want := res.Trailer, (Header{
+               "Server-Trailer-A": {"valuea"},
+               "Server-Trailer-B": nil,
+               "Server-Trailer-C": {"valuec"},
+       }); !reflect.DeepEqual(got, want) {
+               t.Errorf("Trailer after body read = %v; want %v", got, want)
+       }
+}
+
+// Don't allow a Body.Read after Body.Close. Issue 13648.
+func TestResponseBodyReadAfterClose_h1(t *testing.T) { testResponseBodyReadAfterClose(t, h1Mode) }
+func TestResponseBodyReadAfterClose_h2(t *testing.T) { testResponseBodyReadAfterClose(t, h2Mode) }
+
+func testResponseBodyReadAfterClose(t *testing.T, h2 bool) {
+       defer afterTest(t)
+       const body = "Some body"
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+               io.WriteString(w, body)
+       }))
+       defer cst.close()
+       res, err := cst.c.Get(cst.ts.URL)
+       if err != nil {
+               t.Fatal(err)
+       }
+       res.Body.Close()
+       data, err := ioutil.ReadAll(res.Body)
+       if len(data) != 0 || err == nil {
+               t.Fatalf("ReadAll returned %q, %v; want error", data, err)
+       }
+}
+
+func TestConcurrentReadWriteReqBody_h1(t *testing.T) { testConcurrentReadWriteReqBody(t, h1Mode) }
+func TestConcurrentReadWriteReqBody_h2(t *testing.T) { testConcurrentReadWriteReqBody(t, h2Mode) }
+func testConcurrentReadWriteReqBody(t *testing.T, h2 bool) {
+       defer afterTest(t)
+       const reqBody = "some request body"
+       const resBody = "some response body"
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+               var wg sync.WaitGroup
+               wg.Add(2)
+               didRead := make(chan bool, 1)
+               // Read in one goroutine.
+               go func() {
+                       defer wg.Done()
+                       data, err := ioutil.ReadAll(r.Body)
+                       if string(data) != reqBody {
+                               t.Errorf("Handler read %q; want %q", data, reqBody)
+                       }
+                       if err != nil {
+                               t.Errorf("Handler Read: %v", err)
+                       }
+                       didRead <- true
+               }()
+               // Write in another goroutine.
+               go func() {
+                       defer wg.Done()
+                       if !h2 {
+                               // our HTTP/1 implementation intentionally
+                               // doesn't permit writes during read (mostly
+                               // due to it being undefined); if that is ever
+                               // relaxed, change this.
+                               <-didRead
+                       }
+                       io.WriteString(w, resBody)
+               }()
+               wg.Wait()
+       }))
+       defer cst.close()
+       req, _ := NewRequest("POST", cst.ts.URL, strings.NewReader(reqBody))
+       req.Header.Add("Expect", "100-continue") // just to complicate things
+       res, err := cst.c.Do(req)
+       if err != nil {
+               t.Fatal(err)
+       }
+       data, err := ioutil.ReadAll(res.Body)
+       defer res.Body.Close()
+       if err != nil {
+               t.Fatal(err)
+       }
+       if string(data) != resBody {
+               t.Errorf("read %q; want %q", data, resBody)
+       }
+}
+
+func TestConnectRequest_h1(t *testing.T) { testConnectRequest(t, h1Mode) }
+func TestConnectRequest_h2(t *testing.T) { testConnectRequest(t, h2Mode) }
+func testConnectRequest(t *testing.T, h2 bool) {
+       defer afterTest(t)
+       gotc := make(chan *Request, 1)
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+               gotc <- r
+       }))
+       defer cst.close()
+
+       u, err := url.Parse(cst.ts.URL)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       tests := []struct {
+               req  *Request
+               want string
+       }{
+               {
+                       req: &Request{
+                               Method: "CONNECT",
+                               Header: Header{},
+                               URL:    u,
+                       },
+                       want: u.Host,
+               },
+               {
+                       req: &Request{
+                               Method: "CONNECT",
+                               Header: Header{},
+                               URL:    u,
+                               Host:   "example.com:123",
+                       },
+                       want: "example.com:123",
+               },
+       }
+
+       for i, tt := range tests {
+               res, err := cst.c.Do(tt.req)
+               if err != nil {
+                       t.Errorf("%d. RoundTrip = %v", i, err)
+                       continue
+               }
+               res.Body.Close()
+               req := <-gotc
+               if req.Method != "CONNECT" {
+                       t.Errorf("method = %q; want CONNECT", req.Method)
+               }
+               if req.Host != tt.want {
+                       t.Errorf("Host = %q; want %q", req.Host, tt.want)
+               }
+               if req.URL.Host != tt.want {
+                       t.Errorf("URL.Host = %q; want %q", req.URL.Host, tt.want)
+               }
+       }
+}
+
+func TestTransportUserAgent_h1(t *testing.T) { testTransportUserAgent(t, h1Mode) }
+func TestTransportUserAgent_h2(t *testing.T) { testTransportUserAgent(t, h2Mode) }
+func testTransportUserAgent(t *testing.T, h2 bool) {
+       defer afterTest(t)
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+               fmt.Fprintf(w, "%q", r.Header["User-Agent"])
+       }))
+       defer cst.close()
+
+       either := func(a, b string) string {
+               if h2 {
+                       return b
+               }
+               return a
+       }
+
+       tests := []struct {
+               setup func(*Request)
+               want  string
+       }{
+               {
+                       func(r *Request) {},
+                       either(`["Go-http-client/1.1"]`, `["Go-http-client/2.0"]`),
+               },
+               {
+                       func(r *Request) { r.Header.Set("User-Agent", "foo/1.2.3") },
+                       `["foo/1.2.3"]`,
+               },
+               {
+                       func(r *Request) { r.Header["User-Agent"] = []string{"single", "or", "multiple"} },
+                       `["single"]`,
+               },
+               {
+                       func(r *Request) { r.Header.Set("User-Agent", "") },
+                       `[]`,
+               },
+               {
+                       func(r *Request) { r.Header["User-Agent"] = nil },
+                       `[]`,
+               },
+       }
+       for i, tt := range tests {
+               req, _ := NewRequest("GET", cst.ts.URL, nil)
+               tt.setup(req)
+               res, err := cst.c.Do(req)
+               if err != nil {
+                       t.Errorf("%d. RoundTrip = %v", i, err)
+                       continue
+               }
+               slurp, err := ioutil.ReadAll(res.Body)
+               res.Body.Close()
+               if err != nil {
+                       t.Errorf("%d. read body = %v", i, err)
+                       continue
+               }
+               if string(slurp) != tt.want {
+                       t.Errorf("%d. body mismatch.\n got: %s\nwant: %s\n", i, slurp, tt.want)
+               }
+       }
+}
+
+func TestStarRequestFoo_h1(t *testing.T)     { testStarRequest(t, "FOO", h1Mode) }
+func TestStarRequestFoo_h2(t *testing.T)     { testStarRequest(t, "FOO", h2Mode) }
+func TestStarRequestOptions_h1(t *testing.T) { testStarRequest(t, "OPTIONS", h1Mode) }
+func TestStarRequestOptions_h2(t *testing.T) { testStarRequest(t, "OPTIONS", h2Mode) }
+func testStarRequest(t *testing.T, method string, h2 bool) {
+       defer afterTest(t)
+       gotc := make(chan *Request, 1)
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+               w.Header().Set("foo", "bar")
+               gotc <- r
+               w.(Flusher).Flush()
+       }))
+       defer cst.close()
+
+       u, err := url.Parse(cst.ts.URL)
+       if err != nil {
+               t.Fatal(err)
+       }
+       u.Path = "*"
+
+       req := &Request{
+               Method: method,
+               Header: Header{},
+               URL:    u,
+       }
+
+       res, err := cst.c.Do(req)
+       if err != nil {
+               t.Fatalf("RoundTrip = %v", err)
+       }
+       res.Body.Close()
+
+       wantFoo := "bar"
+       wantLen := int64(-1)
+       if method == "OPTIONS" {
+               wantFoo = ""
+               wantLen = 0
+       }
+       if res.StatusCode != 200 {
+               t.Errorf("status code = %v; want %d", res.Status, 200)
+       }
+       if res.ContentLength != wantLen {
+               t.Errorf("content length = %v; want %d", res.ContentLength, wantLen)
+       }
+       if got := res.Header.Get("foo"); got != wantFoo {
+               t.Errorf("response \"foo\" header = %q; want %q", got, wantFoo)
+       }
+       select {
+       case req = <-gotc:
+       default:
+               req = nil
+       }
+       if req == nil {
+               if method != "OPTIONS" {
+                       t.Fatalf("handler never got request")
+               }
+               return
+       }
+       if req.Method != method {
+               t.Errorf("method = %q; want %q", req.Method, method)
+       }
+       if req.URL.Path != "*" {
+               t.Errorf("URL.Path = %q; want *", req.URL.Path)
+       }
+       if req.RequestURI != "*" {
+               t.Errorf("RequestURI = %q; want *", req.RequestURI)
+       }
+}
+
+// Issue 13957
+func TestTransportDiscardsUnneededConns(t *testing.T) {
+       defer afterTest(t)
+       cst := newClientServerTest(t, h2Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
+               fmt.Fprintf(w, "Hello, %v", r.RemoteAddr)
+       }))
+       defer cst.close()
+
+       var numOpen, numClose int32 // atomic
+
+       tlsConfig := &tls.Config{InsecureSkipVerify: true}
+       tr := &Transport{
+               TLSClientConfig: tlsConfig,
+               DialTLS: func(_, addr string) (net.Conn, error) {
+                       time.Sleep(10 * time.Millisecond)
+                       rc, err := net.Dial("tcp", addr)
+                       if err != nil {
+                               return nil, err
+                       }
+                       atomic.AddInt32(&numOpen, 1)
+                       c := noteCloseConn{rc, func() { atomic.AddInt32(&numClose, 1) }}
+                       return tls.Client(c, tlsConfig), nil
+               },
+       }
+       if err := ExportHttp2ConfigureTransport(tr); err != nil {
+               t.Fatal(err)
+       }
+       defer tr.CloseIdleConnections()
+
+       c := &Client{Transport: tr}
+
+       const N = 10
+       gotBody := make(chan string, N)
+       var wg sync.WaitGroup
+       for i := 0; i < N; i++ {
+               wg.Add(1)
+               go func() {
+                       defer wg.Done()
+                       resp, err := c.Get(cst.ts.URL)
+                       if err != nil {
+                               t.Errorf("Get: %v", err)
+                               return
+                       }
+                       defer resp.Body.Close()
+                       slurp, err := ioutil.ReadAll(resp.Body)
+                       if err != nil {
+                               t.Error(err)
+                       }
+                       gotBody <- string(slurp)
+               }()
+       }
+       wg.Wait()
+       close(gotBody)
+
+       var last string
+       for got := range gotBody {
+               if last == "" {
+                       last = got
+                       continue
+               }
+               if got != last {
+                       t.Errorf("Response body changed: %q -> %q", last, got)
+               }
+       }
+
+       var open, close int32
+       for i := 0; i < 150; i++ {
+               open, close = atomic.LoadInt32(&numOpen), atomic.LoadInt32(&numClose)
+               if open < 1 {
+                       t.Fatalf("open = %d; want at least", open)
+               }
+               if close == open-1 {
+                       // Success
+                       return
+               }
+               time.Sleep(10 * time.Millisecond)
+       }
+       t.Errorf("%d connections opened, %d closed; want %d to close", open, close, open-1)
+}
+
+// tests that Transport doesn't retain a pointer to the provided request.
+func TestTransportGCRequest_h1(t *testing.T) { testTransportGCRequest(t, h1Mode) }
+func TestTransportGCRequest_h2(t *testing.T) { testTransportGCRequest(t, h2Mode) }
+func testTransportGCRequest(t *testing.T, h2 bool) {
+       if runtime.Compiler == "gccgo" {
+               t.Skip("skipping on gccgo because conservative GC means that finalizer may never run")
+       }
+
+       defer afterTest(t)
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+               ioutil.ReadAll(r.Body)
+               io.WriteString(w, "Hello.")
+       }))
+       defer cst.close()
+
+       didGC := make(chan struct{})
+       (func() {
+               body := strings.NewReader("some body")
+               req, _ := NewRequest("POST", cst.ts.URL, body)
+               runtime.SetFinalizer(req, func(*Request) { close(didGC) })
+               res, err := cst.c.Do(req)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               if _, err := ioutil.ReadAll(res.Body); err != nil {
+                       t.Fatal(err)
+               }
+               if err := res.Body.Close(); err != nil {
+                       t.Fatal(err)
+               }
+       })()
+       timeout := time.NewTimer(5 * time.Second)
+       defer timeout.Stop()
+       for {
+               select {
+               case <-didGC:
+                       return
+               case <-time.After(100 * time.Millisecond):
+                       runtime.GC()
+               case <-timeout.C:
+                       t.Fatal("never saw GC of request")
+               }
+       }
+}
+
+type noteCloseConn struct {
+       net.Conn
+       closeFunc func()
+}
+
+func (x noteCloseConn) Close() error {
+       x.closeFunc()
+       return x.Conn.Close()
+}
index b1216e8dafa5b701a59cd4f167085d1bfcd8553e..4ec8272f62861b7c397278e9479acc99928809b0 100644 (file)
@@ -76,5 +76,20 @@ custom Server:
                MaxHeaderBytes: 1 << 20,
        }
        log.Fatal(s.ListenAndServe())
+
+The http package has transparent support for the HTTP/2 protocol when
+using HTTPS. Programs that must disable HTTP/2 can do so by setting
+Transport.TLSNextProto (for clients) or Server.TLSNextProto (for
+servers) to a non-nil, empty map. Alternatively, the following GODEBUG
+environment variables are currently supported:
+
+       GODEBUG=http2client=0  # disable HTTP/2 client support
+       GODEBUG=http2server=0  # disable HTTP/2 server support
+       GODEBUG=http2debug=1   # enable verbose HTTP/2 debug logs
+       GODEBUG=http2debug=2   # ... even more verbose, with frame dumps
+
+The GODEBUG variables are not covered by Go's API compatibility promise.
+HTTP/2 support was added in Go 1.6. Please report any issues instead of
+disabling HTTP/2 support: https://golang.org/s/http2bug
 */
 package http
index 0457be50da6a20688c4b80bf14f175a5a7000760..52bccbdce31c5a3139f985140c58e7ebe3733ea1 100644 (file)
@@ -9,11 +9,24 @@ package http
 
 import (
        "net"
-       "net/url"
        "sync"
        "time"
 )
 
+var (
+       DefaultUserAgent              = defaultUserAgent
+       NewLoggingConn                = newLoggingConn
+       ExportAppendTime              = appendTime
+       ExportRefererForURL           = refererForURL
+       ExportServerNewConn           = (*Server).newConn
+       ExportCloseWriteAndWait       = (*conn).closeWriteAndWait
+       ExportErrRequestCanceled      = errRequestCanceled
+       ExportErrRequestCanceledConn  = errRequestCanceledConn
+       ExportServeFile               = serveFile
+       ExportHttp2ConfigureTransport = http2ConfigureTransport
+       ExportHttp2ConfigureServer    = http2ConfigureServer
+)
+
 func init() {
        // We only want to pay for this cost during testing.
        // When not under test, these values are always nil
@@ -21,11 +34,42 @@ func init() {
        testHookMu = new(sync.Mutex)
 }
 
-func NewLoggingConn(baseName string, c net.Conn) net.Conn {
-       return newLoggingConn(baseName, c)
+var (
+       SetEnterRoundTripHook  = hookSetter(&testHookEnterRoundTrip)
+       SetTestHookWaitResLoop = hookSetter(&testHookWaitResLoop)
+       SetRoundTripRetried    = hookSetter(&testHookRoundTripRetried)
+)
+
+func SetReadLoopBeforeNextReadHook(f func()) {
+       testHookMu.Lock()
+       defer testHookMu.Unlock()
+       unnilTestHook(&f)
+       testHookReadLoopBeforeNextRead = f
+}
+
+// SetPendingDialHooks sets the hooks that run before and after handling
+// pending dials.
+func SetPendingDialHooks(before, after func()) {
+       unnilTestHook(&before)
+       unnilTestHook(&after)
+       testHookPrePendingDial, testHookPostPendingDial = before, after
 }
 
-var ExportAppendTime = appendTime
+func SetTestHookServerServe(fn func(*Server, net.Listener)) { testHookServerServe = fn }
+
+func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler {
+       return &timeoutHandler{
+               handler: handler,
+               timeout: func() <-chan time.Time { return ch },
+               // (no body and nil cancelTimer)
+       }
+}
+
+func ResetCachedEnvironment() {
+       httpProxyEnv.reset()
+       httpsProxyEnv.reset()
+       noProxyEnv.reset()
+}
 
 func (t *Transport) NumPendingRequestsForTesting() int {
        t.reqMu.Lock()
@@ -78,55 +122,25 @@ func (t *Transport) RequestIdleConnChForTesting() {
 
 func (t *Transport) PutIdleTestConn() bool {
        c, _ := net.Pipe()
-       return t.putIdleConn(&persistConn{
+       return t.tryPutIdleConn(&persistConn{
                t:        t,
                conn:     c,                   // dummy
                closech:  make(chan struct{}), // so it can be closed
                cacheKey: connectMethodKey{"", "http", "example.com"},
-       })
-}
-
-func SetInstallConnClosedHook(f func()) {
-       testHookPersistConnClosedGotRes = f
+       }) == nil
 }
 
-func SetEnterRoundTripHook(f func()) {
-       testHookEnterRoundTrip = f
-}
-
-func SetReadLoopBeforeNextReadHook(f func()) {
-       testHookMu.Lock()
-       defer testHookMu.Unlock()
-       testHookReadLoopBeforeNextRead = f
-}
-
-func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler {
-       f := func() <-chan time.Time {
-               return ch
+// All test hooks must be non-nil so they can be called directly,
+// but the tests use nil to mean hook disabled.
+func unnilTestHook(f *func()) {
+       if *f == nil {
+               *f = nop
        }
-       return &timeoutHandler{handler, f, ""}
 }
 
-func ResetCachedEnvironment() {
-       httpProxyEnv.reset()
-       httpsProxyEnv.reset()
-       noProxyEnv.reset()
-}
-
-var DefaultUserAgent = defaultUserAgent
-
-func ExportRefererForURL(lastReq, newReq *url.URL) string {
-       return refererForURL(lastReq, newReq)
-}
-
-// SetPendingDialHooks sets the hooks that run before and after handling
-// pending dials.
-func SetPendingDialHooks(before, after func()) {
-       prePendingDial, postPendingDial = before, after
+func hookSetter(dst *func()) func(func()) {
+       return func(fn func()) {
+               unnilTestHook(&fn)
+               *dst = fn
+       }
 }
-
-var ExportServerNewConn = (*Server).newConn
-
-var ExportCloseWriteAndWait = (*conn).closeWriteAndWait
-
-var ExportErrRequestCanceled = errRequestCanceled
index da824ed717e14e257fead4fc58b6550a776d522e..88704245db8742325c426fcad49ecd37e1c8606e 100644 (file)
@@ -56,6 +56,9 @@ func (r *request) parseParams() {
                        return
                }
                text = text[n:]
+               if int(keyLen)+int(valLen) > len(text) {
+                       return
+               }
                key := readString(text, keyLen)
                text = text[keyLen:]
                val := readString(text, valLen)
index de0f7f831f61683a34dd6be8619f25e6e341002a..b6013bfdd519362f71e91f9c79d67991dc4a3f9e 100644 (file)
@@ -254,3 +254,27 @@ func TestChildServeCleansUp(t *testing.T) {
                <-done
        }
 }
+
+type rwNopCloser struct {
+       io.Reader
+       io.Writer
+}
+
+func (rwNopCloser) Close() error {
+       return nil
+}
+
+// Verifies it doesn't crash.  Issue 11824.
+func TestMalformedParams(t *testing.T) {
+       input := []byte{
+               // beginRequest, requestId=1, contentLength=8, role=1, keepConn=1
+               1, 1, 0, 1, 0, 8, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0,
+               // params, requestId=1, contentLength=10, k1Len=50, v1Len=50 (malformed, wrong length)
+               1, 4, 0, 1, 0, 10, 0, 0, 50, 50, 3, 4, 5, 6, 7, 8, 9, 10,
+               // end of params
+               1, 4, 0, 1, 0, 0, 0, 0,
+       }
+       rw := rwNopCloser{bytes.NewReader(input), ioutil.Discard}
+       c := newChild(rw, http.DefaultServeMux)
+       c.serve()
+}
index 75720234c25d8083b40b3a37ec85f815fb6b0da2..f61c138c1d944390f3fc1f29d9e7d382f1e6e601 100644 (file)
@@ -17,6 +17,7 @@ import (
        "os"
        "path"
        "path/filepath"
+       "sort"
        "strconv"
        "strings"
        "time"
@@ -62,30 +63,34 @@ type FileSystem interface {
 type File interface {
        io.Closer
        io.Reader
+       io.Seeker
        Readdir(count int) ([]os.FileInfo, error)
-       Seek(offset int64, whence int) (int64, error)
        Stat() (os.FileInfo, error)
 }
 
 func dirList(w ResponseWriter, f File) {
+       dirs, err := f.Readdir(-1)
+       if err != nil {
+               // TODO: log err.Error() to the Server.ErrorLog, once it's possible
+               // for a handler to get at its Server via the ResponseWriter. See
+               // Issue 12438.
+               Error(w, "Error reading directory", StatusInternalServerError)
+               return
+       }
+       sort.Sort(byName(dirs))
+
        w.Header().Set("Content-Type", "text/html; charset=utf-8")
        fmt.Fprintf(w, "<pre>\n")
-       for {
-               dirs, err := f.Readdir(100)
-               if err != nil || len(dirs) == 0 {
-                       break
-               }
-               for _, d := range dirs {
-                       name := d.Name()
-                       if d.IsDir() {
-                               name += "/"
-                       }
-                       // name may contain '?' or '#', which must be escaped to remain
-                       // part of the URL path, and not indicate the start of a query
-                       // string or fragment.
-                       url := url.URL{Path: name}
-                       fmt.Fprintf(w, "<a href=\"%s\">%s</a>\n", url.String(), htmlReplacer.Replace(name))
+       for _, d := range dirs {
+               name := d.Name()
+               if d.IsDir() {
+                       name += "/"
                }
+               // name may contain '?' or '#', which must be escaped to remain
+               // part of the URL path, and not indicate the start of a query
+               // string or fragment.
+               url := url.URL{Path: name}
+               fmt.Fprintf(w, "<a href=\"%s\">%s</a>\n", url.String(), htmlReplacer.Replace(name))
        }
        fmt.Fprintf(w, "</pre>\n")
 }
@@ -364,8 +369,8 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
        }
        defer f.Close()
 
-       d, err1 := f.Stat()
-       if err1 != nil {
+       d, err := f.Stat()
+       if err != nil {
                msg, code := toHTTPError(err)
                Error(w, msg, code)
                return
@@ -446,15 +451,44 @@ func localRedirect(w ResponseWriter, r *Request, newPath string) {
 // ServeFile replies to the request with the contents of the named
 // file or directory.
 //
+// If the provided file or direcory name is a relative path, it is
+// interpreted relative to the current directory and may ascend to parent
+// directories. If the provided name is constructed from user input, it
+// should be sanitized before calling ServeFile. As a precaution, ServeFile
+// will reject requests where r.URL.Path contains a ".." path element.
+//
 // As a special case, ServeFile redirects any request where r.URL.Path
 // ends in "/index.html" to the same path, without the final
 // "index.html". To avoid such redirects either modify the path or
 // use ServeContent.
 func ServeFile(w ResponseWriter, r *Request, name string) {
+       if containsDotDot(r.URL.Path) {
+               // Too many programs use r.URL.Path to construct the argument to
+               // serveFile. Reject the request under the assumption that happened
+               // here and ".." may not be wanted.
+               // Note that name might not contain "..", for example if code (still
+               // incorrectly) used filepath.Join(myDir, r.URL.Path).
+               Error(w, "invalid URL path", StatusBadRequest)
+               return
+       }
        dir, file := filepath.Split(name)
        serveFile(w, r, Dir(dir), file, false)
 }
 
+func containsDotDot(v string) bool {
+       if !strings.Contains(v, "..") {
+               return false
+       }
+       for _, ent := range strings.FieldsFunc(v, isSlashRune) {
+               if ent == ".." {
+                       return true
+               }
+       }
+       return false
+}
+
+func isSlashRune(r rune) bool { return r == '/' || r == '\\' }
+
 type fileHandler struct {
        root FileSystem
 }
@@ -585,3 +619,9 @@ func sumRangesSize(ranges []httpRange) (size int64) {
        }
        return
 }
+
+type byName []os.FileInfo
+
+func (s byName) Len() int           { return len(s) }
+func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() }
+func (s byName) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
index 538f34d72011d1a19a75222a2aca119656698cc5..cf5b63c9f7588b96cbd99a9303dfe316850935e1 100644 (file)
@@ -5,6 +5,7 @@
 package http_test
 
 import (
+       "bufio"
        "bytes"
        "errors"
        "fmt"
@@ -177,6 +178,36 @@ Cases:
        }
 }
 
+func TestServeFile_DotDot(t *testing.T) {
+       tests := []struct {
+               req        string
+               wantStatus int
+       }{
+               {"/testdata/file", 200},
+               {"/../file", 400},
+               {"/..", 400},
+               {"/../", 400},
+               {"/../foo", 400},
+               {"/..\\foo", 400},
+               {"/file/a", 200},
+               {"/file/a..", 200},
+               {"/file/a/..", 400},
+               {"/file/a\\..", 400},
+       }
+       for _, tt := range tests {
+               req, err := ReadRequest(bufio.NewReader(strings.NewReader("GET " + tt.req + " HTTP/1.1\r\nHost: foo\r\n\r\n")))
+               if err != nil {
+                       t.Errorf("bad request %q: %v", tt.req, err)
+                       continue
+               }
+               rec := httptest.NewRecorder()
+               ServeFile(rec, req, "testdata/file")
+               if rec.Code != tt.wantStatus {
+                       t.Errorf("for request %q, status = %d; want %d", tt.req, rec.Code, tt.wantStatus)
+               }
+       }
+}
+
 var fsRedirectTestData = []struct {
        original, redirect string
 }{
@@ -283,6 +314,49 @@ func TestFileServerEscapesNames(t *testing.T) {
        }
 }
 
+func TestFileServerSortsNames(t *testing.T) {
+       defer afterTest(t)
+       const contents = "I am a fake file"
+       dirMod := time.Unix(123, 0).UTC()
+       fileMod := time.Unix(1000000000, 0).UTC()
+       fs := fakeFS{
+               "/": &fakeFileInfo{
+                       dir:     true,
+                       modtime: dirMod,
+                       ents: []*fakeFileInfo{
+                               {
+                                       basename: "b",
+                                       modtime:  fileMod,
+                                       contents: contents,
+                               },
+                               {
+                                       basename: "a",
+                                       modtime:  fileMod,
+                                       contents: contents,
+                               },
+                       },
+               },
+       }
+
+       ts := httptest.NewServer(FileServer(&fs))
+       defer ts.Close()
+
+       res, err := Get(ts.URL)
+       if err != nil {
+               t.Fatalf("Get: %v", err)
+       }
+       defer res.Body.Close()
+
+       b, err := ioutil.ReadAll(res.Body)
+       if err != nil {
+               t.Fatalf("read Body: %v", err)
+       }
+       s := string(b)
+       if !strings.Contains(s, "<a href=\"a\">a</a>\n<a href=\"b\">b</a>") {
+               t.Errorf("output appears to be unsorted:\n%s", s)
+       }
+}
+
 func mustRemoveAll(dir string) {
        err := os.RemoveAll(dir)
        if err != nil {
@@ -434,14 +508,27 @@ func TestServeFileFromCWD(t *testing.T) {
        }
 }
 
-func TestServeFileWithContentEncoding(t *testing.T) {
+// Tests that ServeFile doesn't add a Content-Length if a Content-Encoding is
+// specified.
+func TestServeFileWithContentEncoding_h1(t *testing.T) { testServeFileWithContentEncoding(t, h1Mode) }
+func TestServeFileWithContentEncoding_h2(t *testing.T) { testServeFileWithContentEncoding(t, h2Mode) }
+func testServeFileWithContentEncoding(t *testing.T, h2 bool) {
        defer afterTest(t)
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
                w.Header().Set("Content-Encoding", "foo")
                ServeFile(w, r, "testdata/file")
+
+               // Because the testdata is so small, it would fit in
+               // both the h1 and h2 Server's write buffers. For h1,
+               // sendfile is used, though, forcing a header flush at
+               // the io.Copy. http2 doesn't do a header flush so
+               // buffers all 11 bytes and then adds its own
+               // Content-Length. To prevent the Server's
+               // Content-Length and test ServeFile only, flush here.
+               w.(Flusher).Flush()
        }))
-       defer ts.Close()
-       resp, err := Get(ts.URL)
+       defer cst.close()
+       resp, err := cst.c.Get(cst.ts.URL)
        if err != nil {
                t.Fatal(err)
        }
@@ -807,6 +894,28 @@ func TestServeContent(t *testing.T) {
        }
 }
 
+// Issue 12991
+func TestServerFileStatError(t *testing.T) {
+       rec := httptest.NewRecorder()
+       r, _ := NewRequest("GET", "http://foo/", nil)
+       redirect := false
+       name := "file.txt"
+       fs := issue12991FS{}
+       ExportServeFile(rec, r, fs, name, redirect)
+       if body := rec.Body.String(); !strings.Contains(body, "403") || !strings.Contains(body, "Forbidden") {
+               t.Errorf("wanted 403 forbidden message; got: %s", body)
+       }
+}
+
+type issue12991FS struct{}
+
+func (issue12991FS) Open(string) (File, error) { return issue12991File{}, nil }
+
+type issue12991File struct{ File }
+
+func (issue12991File) Stat() (os.FileInfo, error) { return nil, os.ErrPermission }
+func (issue12991File) Close() error               { return nil }
+
 func TestServeContentErrorMessages(t *testing.T) {
        defer afterTest(t)
        fs := fakeFS{
@@ -852,13 +961,16 @@ func TestLinuxSendfile(t *testing.T) {
        }
        defer ln.Close()
 
-       trace := "trace=sendfile"
-       if runtime.GOARCH != "alpha" {
-               trace = trace + ",sendfile64"
+       syscalls := "sendfile,sendfile64"
+       switch runtime.GOARCH {
+       case "mips64", "mips64le", "alpha":
+               // mips64 strace doesn't support sendfile64 and will error out
+               // if we specify that with `-e trace='.
+               syscalls = "sendfile"
        }
 
        var buf bytes.Buffer
-       child := exec.Command("strace", "-f", "-q", "-e", trace, os.Args[0], "-test.run=TestLinuxSendfileChild")
+       child := exec.Command("strace", "-f", "-q", "-e", "trace="+syscalls, os.Args[0], "-test.run=TestLinuxSendfileChild")
        child.ExtraFiles = append(child.ExtraFiles, lnf)
        child.Env = append([]string{"GO_WANT_HELPER_PROCESS=1"}, os.Environ()...)
        child.Stdout = &buf
@@ -878,7 +990,7 @@ func TestLinuxSendfile(t *testing.T) {
        res.Body.Close()
 
        // Force child to exit cleanly.
-       Get(fmt.Sprintf("http://%s/quit", ln.Addr()))
+       Post(fmt.Sprintf("http://%s/quit", ln.Addr()), "", nil)
        child.Wait()
 
        rx := regexp.MustCompile(`sendfile(64)?\(\d+,\s*\d+,\s*NULL,\s*\d+\)\s*=\s*\d+\s*\n`)
diff --git a/libgo/go/net/http/h2_bundle.go b/libgo/go/net/http/h2_bundle.go
new file mode 100644 (file)
index 0000000..e723629
--- /dev/null
@@ -0,0 +1,6530 @@
+// Code generated by golang.org/x/tools/cmd/bundle command:
+//   $ bundle golang.org/x/net/http2 net/http http2
+
+// Package http2 implements the HTTP/2 protocol.
+//
+// This package is low-level and intended to be used directly by very
+// few people. Most users will use it indirectly through the automatic
+// use by the net/http package (from Go 1.6 and later).
+// For use in earlier Go versions see ConfigureServer. (Transport support
+// requires Go 1.6 or later)
+//
+// See https://http2.github.io/ for more information on HTTP/2.
+//
+// See https://http2.golang.org/ for a test server running this code.
+//
+
+package http
+
+import (
+       "bufio"
+       "bytes"
+       "compress/gzip"
+       "crypto/tls"
+       "encoding/binary"
+       "errors"
+       "fmt"
+       "internal/golang.org/x/net/http2/hpack"
+       "io"
+       "io/ioutil"
+       "log"
+       "net"
+       "net/textproto"
+       "net/url"
+       "os"
+       "reflect"
+       "runtime"
+       "sort"
+       "strconv"
+       "strings"
+       "sync"
+       "time"
+)
+
+// ClientConnPool manages a pool of HTTP/2 client connections.
+type http2ClientConnPool interface {
+       GetClientConn(req *Request, addr string) (*http2ClientConn, error)
+       MarkDead(*http2ClientConn)
+}
+
+// TODO: use singleflight for dialing and addConnCalls?
+type http2clientConnPool struct {
+       t *http2Transport
+
+       mu sync.Mutex // TODO: maybe switch to RWMutex
+       // TODO: add support for sharing conns based on cert names
+       // (e.g. share conn for googleapis.com and appspot.com)
+       conns        map[string][]*http2ClientConn // key is host:port
+       dialing      map[string]*http2dialCall     // currently in-flight dials
+       keys         map[*http2ClientConn][]string
+       addConnCalls map[string]*http2addConnCall // in-flight addConnIfNeede calls
+}
+
+func (p *http2clientConnPool) GetClientConn(req *Request, addr string) (*http2ClientConn, error) {
+       return p.getClientConn(req, addr, http2dialOnMiss)
+}
+
+const (
+       http2dialOnMiss   = true
+       http2noDialOnMiss = false
+)
+
+func (p *http2clientConnPool) getClientConn(_ *Request, addr string, dialOnMiss bool) (*http2ClientConn, error) {
+       p.mu.Lock()
+       for _, cc := range p.conns[addr] {
+               if cc.CanTakeNewRequest() {
+                       p.mu.Unlock()
+                       return cc, nil
+               }
+       }
+       if !dialOnMiss {
+               p.mu.Unlock()
+               return nil, http2ErrNoCachedConn
+       }
+       call := p.getStartDialLocked(addr)
+       p.mu.Unlock()
+       <-call.done
+       return call.res, call.err
+}
+
+// dialCall is an in-flight Transport dial call to a host.
+type http2dialCall struct {
+       p    *http2clientConnPool
+       done chan struct{}    // closed when done
+       res  *http2ClientConn // valid after done is closed
+       err  error            // valid after done is closed
+}
+
+// requires p.mu is held.
+func (p *http2clientConnPool) getStartDialLocked(addr string) *http2dialCall {
+       if call, ok := p.dialing[addr]; ok {
+
+               return call
+       }
+       call := &http2dialCall{p: p, done: make(chan struct{})}
+       if p.dialing == nil {
+               p.dialing = make(map[string]*http2dialCall)
+       }
+       p.dialing[addr] = call
+       go call.dial(addr)
+       return call
+}
+
+// run in its own goroutine.
+func (c *http2dialCall) dial(addr string) {
+       c.res, c.err = c.p.t.dialClientConn(addr)
+       close(c.done)
+
+       c.p.mu.Lock()
+       delete(c.p.dialing, addr)
+       if c.err == nil {
+               c.p.addConnLocked(addr, c.res)
+       }
+       c.p.mu.Unlock()
+}
+
+// addConnIfNeeded makes a NewClientConn out of c if a connection for key doesn't
+// already exist. It coalesces concurrent calls with the same key.
+// This is used by the http1 Transport code when it creates a new connection. Because
+// the http1 Transport doesn't de-dup TCP dials to outbound hosts (because it doesn't know
+// the protocol), it can get into a situation where it has multiple TLS connections.
+// This code decides which ones live or die.
+// The return value used is whether c was used.
+// c is never closed.
+func (p *http2clientConnPool) addConnIfNeeded(key string, t *http2Transport, c *tls.Conn) (used bool, err error) {
+       p.mu.Lock()
+       for _, cc := range p.conns[key] {
+               if cc.CanTakeNewRequest() {
+                       p.mu.Unlock()
+                       return false, nil
+               }
+       }
+       call, dup := p.addConnCalls[key]
+       if !dup {
+               if p.addConnCalls == nil {
+                       p.addConnCalls = make(map[string]*http2addConnCall)
+               }
+               call = &http2addConnCall{
+                       p:    p,
+                       done: make(chan struct{}),
+               }
+               p.addConnCalls[key] = call
+               go call.run(t, key, c)
+       }
+       p.mu.Unlock()
+
+       <-call.done
+       if call.err != nil {
+               return false, call.err
+       }
+       return !dup, nil
+}
+
+type http2addConnCall struct {
+       p    *http2clientConnPool
+       done chan struct{} // closed when done
+       err  error
+}
+
+func (c *http2addConnCall) run(t *http2Transport, key string, tc *tls.Conn) {
+       cc, err := t.NewClientConn(tc)
+
+       p := c.p
+       p.mu.Lock()
+       if err != nil {
+               c.err = err
+       } else {
+               p.addConnLocked(key, cc)
+       }
+       delete(p.addConnCalls, key)
+       p.mu.Unlock()
+       close(c.done)
+}
+
+func (p *http2clientConnPool) addConn(key string, cc *http2ClientConn) {
+       p.mu.Lock()
+       p.addConnLocked(key, cc)
+       p.mu.Unlock()
+}
+
+// p.mu must be held
+func (p *http2clientConnPool) addConnLocked(key string, cc *http2ClientConn) {
+       for _, v := range p.conns[key] {
+               if v == cc {
+                       return
+               }
+       }
+       if p.conns == nil {
+               p.conns = make(map[string][]*http2ClientConn)
+       }
+       if p.keys == nil {
+               p.keys = make(map[*http2ClientConn][]string)
+       }
+       p.conns[key] = append(p.conns[key], cc)
+       p.keys[cc] = append(p.keys[cc], key)
+}
+
+func (p *http2clientConnPool) MarkDead(cc *http2ClientConn) {
+       p.mu.Lock()
+       defer p.mu.Unlock()
+       for _, key := range p.keys[cc] {
+               vv, ok := p.conns[key]
+               if !ok {
+                       continue
+               }
+               newList := http2filterOutClientConn(vv, cc)
+               if len(newList) > 0 {
+                       p.conns[key] = newList
+               } else {
+                       delete(p.conns, key)
+               }
+       }
+       delete(p.keys, cc)
+}
+
+func (p *http2clientConnPool) closeIdleConnections() {
+       p.mu.Lock()
+       defer p.mu.Unlock()
+
+       for _, vv := range p.conns {
+               for _, cc := range vv {
+                       cc.closeIfIdle()
+               }
+       }
+}
+
+func http2filterOutClientConn(in []*http2ClientConn, exclude *http2ClientConn) []*http2ClientConn {
+       out := in[:0]
+       for _, v := range in {
+               if v != exclude {
+                       out = append(out, v)
+               }
+       }
+
+       if len(in) != len(out) {
+               in[len(in)-1] = nil
+       }
+       return out
+}
+
+func http2configureTransport(t1 *Transport) (*http2Transport, error) {
+       connPool := new(http2clientConnPool)
+       t2 := &http2Transport{
+               ConnPool: http2noDialClientConnPool{connPool},
+               t1:       t1,
+       }
+       connPool.t = t2
+       if err := http2registerHTTPSProtocol(t1, http2noDialH2RoundTripper{t2}); err != nil {
+               return nil, err
+       }
+       if t1.TLSClientConfig == nil {
+               t1.TLSClientConfig = new(tls.Config)
+       }
+       if !http2strSliceContains(t1.TLSClientConfig.NextProtos, "h2") {
+               t1.TLSClientConfig.NextProtos = append([]string{"h2"}, t1.TLSClientConfig.NextProtos...)
+       }
+       if !http2strSliceContains(t1.TLSClientConfig.NextProtos, "http/1.1") {
+               t1.TLSClientConfig.NextProtos = append(t1.TLSClientConfig.NextProtos, "http/1.1")
+       }
+       upgradeFn := func(authority string, c *tls.Conn) RoundTripper {
+               addr := http2authorityAddr(authority)
+               if used, err := connPool.addConnIfNeeded(addr, t2, c); err != nil {
+                       go c.Close()
+                       return http2erringRoundTripper{err}
+               } else if !used {
+
+                       go c.Close()
+               }
+               return t2
+       }
+       if m := t1.TLSNextProto; len(m) == 0 {
+               t1.TLSNextProto = map[string]func(string, *tls.Conn) RoundTripper{
+                       "h2": upgradeFn,
+               }
+       } else {
+               m["h2"] = upgradeFn
+       }
+       return t2, nil
+}
+
+// registerHTTPSProtocol calls Transport.RegisterProtocol but
+// convering panics into errors.
+func http2registerHTTPSProtocol(t *Transport, rt RoundTripper) (err error) {
+       defer func() {
+               if e := recover(); e != nil {
+                       err = fmt.Errorf("%v", e)
+               }
+       }()
+       t.RegisterProtocol("https", rt)
+       return nil
+}
+
+// noDialClientConnPool is an implementation of http2.ClientConnPool
+// which never dials.  We let the HTTP/1.1 client dial and use its TLS
+// connection instead.
+type http2noDialClientConnPool struct{ *http2clientConnPool }
+
+func (p http2noDialClientConnPool) GetClientConn(req *Request, addr string) (*http2ClientConn, error) {
+       return p.getClientConn(req, addr, http2noDialOnMiss)
+}
+
+// noDialH2RoundTripper is a RoundTripper which only tries to complete the request
+// if there's already has a cached connection to the host.
+type http2noDialH2RoundTripper struct{ t *http2Transport }
+
+func (rt http2noDialH2RoundTripper) RoundTrip(req *Request) (*Response, error) {
+       res, err := rt.t.RoundTrip(req)
+       if err == http2ErrNoCachedConn {
+               return nil, ErrSkipAltProtocol
+       }
+       return res, err
+}
+
+// An ErrCode is an unsigned 32-bit error code as defined in the HTTP/2 spec.
+type http2ErrCode uint32
+
+const (
+       http2ErrCodeNo                 http2ErrCode = 0x0
+       http2ErrCodeProtocol           http2ErrCode = 0x1
+       http2ErrCodeInternal           http2ErrCode = 0x2
+       http2ErrCodeFlowControl        http2ErrCode = 0x3
+       http2ErrCodeSettingsTimeout    http2ErrCode = 0x4
+       http2ErrCodeStreamClosed       http2ErrCode = 0x5
+       http2ErrCodeFrameSize          http2ErrCode = 0x6
+       http2ErrCodeRefusedStream      http2ErrCode = 0x7
+       http2ErrCodeCancel             http2ErrCode = 0x8
+       http2ErrCodeCompression        http2ErrCode = 0x9
+       http2ErrCodeConnect            http2ErrCode = 0xa
+       http2ErrCodeEnhanceYourCalm    http2ErrCode = 0xb
+       http2ErrCodeInadequateSecurity http2ErrCode = 0xc
+       http2ErrCodeHTTP11Required     http2ErrCode = 0xd
+)
+
+var http2errCodeName = map[http2ErrCode]string{
+       http2ErrCodeNo:                 "NO_ERROR",
+       http2ErrCodeProtocol:           "PROTOCOL_ERROR",
+       http2ErrCodeInternal:           "INTERNAL_ERROR",
+       http2ErrCodeFlowControl:        "FLOW_CONTROL_ERROR",
+       http2ErrCodeSettingsTimeout:    "SETTINGS_TIMEOUT",
+       http2ErrCodeStreamClosed:       "STREAM_CLOSED",
+       http2ErrCodeFrameSize:          "FRAME_SIZE_ERROR",
+       http2ErrCodeRefusedStream:      "REFUSED_STREAM",
+       http2ErrCodeCancel:             "CANCEL",
+       http2ErrCodeCompression:        "COMPRESSION_ERROR",
+       http2ErrCodeConnect:            "CONNECT_ERROR",
+       http2ErrCodeEnhanceYourCalm:    "ENHANCE_YOUR_CALM",
+       http2ErrCodeInadequateSecurity: "INADEQUATE_SECURITY",
+       http2ErrCodeHTTP11Required:     "HTTP_1_1_REQUIRED",
+}
+
+func (e http2ErrCode) String() string {
+       if s, ok := http2errCodeName[e]; ok {
+               return s
+       }
+       return fmt.Sprintf("unknown error code 0x%x", uint32(e))
+}
+
+// ConnectionError is an error that results in the termination of the
+// entire connection.
+type http2ConnectionError http2ErrCode
+
+func (e http2ConnectionError) Error() string {
+       return fmt.Sprintf("connection error: %s", http2ErrCode(e))
+}
+
+// StreamError is an error that only affects one stream within an
+// HTTP/2 connection.
+type http2StreamError struct {
+       StreamID uint32
+       Code     http2ErrCode
+}
+
+func (e http2StreamError) Error() string {
+       return fmt.Sprintf("stream error: stream ID %d; %v", e.StreamID, e.Code)
+}
+
+// 6.9.1 The Flow Control Window
+// "If a sender receives a WINDOW_UPDATE that causes a flow control
+// window to exceed this maximum it MUST terminate either the stream
+// or the connection, as appropriate. For streams, [...]; for the
+// connection, a GOAWAY frame with a FLOW_CONTROL_ERROR code."
+type http2goAwayFlowError struct{}
+
+func (http2goAwayFlowError) Error() string { return "connection exceeded flow control window size" }
+
+// Errors of this type are only returned by the frame parser functions
+// and converted into ConnectionError(ErrCodeProtocol).
+type http2connError struct {
+       Code   http2ErrCode
+       Reason string
+}
+
+func (e http2connError) Error() string {
+       return fmt.Sprintf("http2: connection error: %v: %v", e.Code, e.Reason)
+}
+
+// fixedBuffer is an io.ReadWriter backed by a fixed size buffer.
+// It never allocates, but moves old data as new data is written.
+type http2fixedBuffer struct {
+       buf  []byte
+       r, w int
+}
+
+var (
+       http2errReadEmpty = errors.New("read from empty fixedBuffer")
+       http2errWriteFull = errors.New("write on full fixedBuffer")
+)
+
+// Read copies bytes from the buffer into p.
+// It is an error to read when no data is available.
+func (b *http2fixedBuffer) Read(p []byte) (n int, err error) {
+       if b.r == b.w {
+               return 0, http2errReadEmpty
+       }
+       n = copy(p, b.buf[b.r:b.w])
+       b.r += n
+       if b.r == b.w {
+               b.r = 0
+               b.w = 0
+       }
+       return n, nil
+}
+
+// Len returns the number of bytes of the unread portion of the buffer.
+func (b *http2fixedBuffer) Len() int {
+       return b.w - b.r
+}
+
+// Write copies bytes from p into the buffer.
+// It is an error to write more data than the buffer can hold.
+func (b *http2fixedBuffer) Write(p []byte) (n int, err error) {
+
+       if b.r > 0 && len(p) > len(b.buf)-b.w {
+               copy(b.buf, b.buf[b.r:b.w])
+               b.w -= b.r
+               b.r = 0
+       }
+
+       n = copy(b.buf[b.w:], p)
+       b.w += n
+       if n < len(p) {
+               err = http2errWriteFull
+       }
+       return n, err
+}
+
+// flow is the flow control window's size.
+type http2flow struct {
+       // n is the number of DATA bytes we're allowed to send.
+       // A flow is kept both on a conn and a per-stream.
+       n int32
+
+       // conn points to the shared connection-level flow that is
+       // shared by all streams on that conn. It is nil for the flow
+       // that's on the conn directly.
+       conn *http2flow
+}
+
+func (f *http2flow) setConnFlow(cf *http2flow) { f.conn = cf }
+
+func (f *http2flow) available() int32 {
+       n := f.n
+       if f.conn != nil && f.conn.n < n {
+               n = f.conn.n
+       }
+       return n
+}
+
+func (f *http2flow) take(n int32) {
+       if n > f.available() {
+               panic("internal error: took too much")
+       }
+       f.n -= n
+       if f.conn != nil {
+               f.conn.n -= n
+       }
+}
+
+// add adds n bytes (positive or negative) to the flow control window.
+// It returns false if the sum would exceed 2^31-1.
+func (f *http2flow) add(n int32) bool {
+       remain := (1<<31 - 1) - f.n
+       if n > remain {
+               return false
+       }
+       f.n += n
+       return true
+}
+
+const http2frameHeaderLen = 9
+
+var http2padZeros = make([]byte, 255) // zeros for padding
+
+// A FrameType is a registered frame type as defined in
+// http://http2.github.io/http2-spec/#rfc.section.11.2
+type http2FrameType uint8
+
+const (
+       http2FrameData         http2FrameType = 0x0
+       http2FrameHeaders      http2FrameType = 0x1
+       http2FramePriority     http2FrameType = 0x2
+       http2FrameRSTStream    http2FrameType = 0x3
+       http2FrameSettings     http2FrameType = 0x4
+       http2FramePushPromise  http2FrameType = 0x5
+       http2FramePing         http2FrameType = 0x6
+       http2FrameGoAway       http2FrameType = 0x7
+       http2FrameWindowUpdate http2FrameType = 0x8
+       http2FrameContinuation http2FrameType = 0x9
+)
+
+var http2frameName = map[http2FrameType]string{
+       http2FrameData:         "DATA",
+       http2FrameHeaders:      "HEADERS",
+       http2FramePriority:     "PRIORITY",
+       http2FrameRSTStream:    "RST_STREAM",
+       http2FrameSettings:     "SETTINGS",
+       http2FramePushPromise:  "PUSH_PROMISE",
+       http2FramePing:         "PING",
+       http2FrameGoAway:       "GOAWAY",
+       http2FrameWindowUpdate: "WINDOW_UPDATE",
+       http2FrameContinuation: "CONTINUATION",
+}
+
+func (t http2FrameType) String() string {
+       if s, ok := http2frameName[t]; ok {
+               return s
+       }
+       return fmt.Sprintf("UNKNOWN_FRAME_TYPE_%d", uint8(t))
+}
+
+// Flags is a bitmask of HTTP/2 flags.
+// The meaning of flags varies depending on the frame type.
+type http2Flags uint8
+
+// Has reports whether f contains all (0 or more) flags in v.
+func (f http2Flags) Has(v http2Flags) bool {
+       return (f & v) == v
+}
+
+// Frame-specific FrameHeader flag bits.
+const (
+       // Data Frame
+       http2FlagDataEndStream http2Flags = 0x1
+       http2FlagDataPadded    http2Flags = 0x8
+
+       // Headers Frame
+       http2FlagHeadersEndStream  http2Flags = 0x1
+       http2FlagHeadersEndHeaders http2Flags = 0x4
+       http2FlagHeadersPadded     http2Flags = 0x8
+       http2FlagHeadersPriority   http2Flags = 0x20
+
+       // Settings Frame
+       http2FlagSettingsAck http2Flags = 0x1
+
+       // Ping Frame
+       http2FlagPingAck http2Flags = 0x1
+
+       // Continuation Frame
+       http2FlagContinuationEndHeaders http2Flags = 0x4
+
+       http2FlagPushPromiseEndHeaders http2Flags = 0x4
+       http2FlagPushPromisePadded     http2Flags = 0x8
+)
+
+var http2flagName = map[http2FrameType]map[http2Flags]string{
+       http2FrameData: {
+               http2FlagDataEndStream: "END_STREAM",
+               http2FlagDataPadded:    "PADDED",
+       },
+       http2FrameHeaders: {
+               http2FlagHeadersEndStream:  "END_STREAM",
+               http2FlagHeadersEndHeaders: "END_HEADERS",
+               http2FlagHeadersPadded:     "PADDED",
+               http2FlagHeadersPriority:   "PRIORITY",
+       },
+       http2FrameSettings: {
+               http2FlagSettingsAck: "ACK",
+       },
+       http2FramePing: {
+               http2FlagPingAck: "ACK",
+       },
+       http2FrameContinuation: {
+               http2FlagContinuationEndHeaders: "END_HEADERS",
+       },
+       http2FramePushPromise: {
+               http2FlagPushPromiseEndHeaders: "END_HEADERS",
+               http2FlagPushPromisePadded:     "PADDED",
+       },
+}
+
+// a frameParser parses a frame given its FrameHeader and payload
+// bytes. The length of payload will always equal fh.Length (which
+// might be 0).
+type http2frameParser func(fh http2FrameHeader, payload []byte) (http2Frame, error)
+
+var http2frameParsers = map[http2FrameType]http2frameParser{
+       http2FrameData:         http2parseDataFrame,
+       http2FrameHeaders:      http2parseHeadersFrame,
+       http2FramePriority:     http2parsePriorityFrame,
+       http2FrameRSTStream:    http2parseRSTStreamFrame,
+       http2FrameSettings:     http2parseSettingsFrame,
+       http2FramePushPromise:  http2parsePushPromise,
+       http2FramePing:         http2parsePingFrame,
+       http2FrameGoAway:       http2parseGoAwayFrame,
+       http2FrameWindowUpdate: http2parseWindowUpdateFrame,
+       http2FrameContinuation: http2parseContinuationFrame,
+}
+
+func http2typeFrameParser(t http2FrameType) http2frameParser {
+       if f := http2frameParsers[t]; f != nil {
+               return f
+       }
+       return http2parseUnknownFrame
+}
+
+// A FrameHeader is the 9 byte header of all HTTP/2 frames.
+//
+// See http://http2.github.io/http2-spec/#FrameHeader
+type http2FrameHeader struct {
+       valid bool // caller can access []byte fields in the Frame
+
+       // Type is the 1 byte frame type. There are ten standard frame
+       // types, but extension frame types may be written by WriteRawFrame
+       // and will be returned by ReadFrame (as UnknownFrame).
+       Type http2FrameType
+
+       // Flags are the 1 byte of 8 potential bit flags per frame.
+       // They are specific to the frame type.
+       Flags http2Flags
+
+       // Length is the length of the frame, not including the 9 byte header.
+       // The maximum size is one byte less than 16MB (uint24), but only
+       // frames up to 16KB are allowed without peer agreement.
+       Length uint32
+
+       // StreamID is which stream this frame is for. Certain frames
+       // are not stream-specific, in which case this field is 0.
+       StreamID uint32
+}
+
+// Header returns h. It exists so FrameHeaders can be embedded in other
+// specific frame types and implement the Frame interface.
+func (h http2FrameHeader) Header() http2FrameHeader { return h }
+
+func (h http2FrameHeader) String() string {
+       var buf bytes.Buffer
+       buf.WriteString("[FrameHeader ")
+       h.writeDebug(&buf)
+       buf.WriteByte(']')
+       return buf.String()
+}
+
+func (h http2FrameHeader) writeDebug(buf *bytes.Buffer) {
+       buf.WriteString(h.Type.String())
+       if h.Flags != 0 {
+               buf.WriteString(" flags=")
+               set := 0
+               for i := uint8(0); i < 8; i++ {
+                       if h.Flags&(1<<i) == 0 {
+                               continue
+                       }
+                       set++
+                       if set > 1 {
+                               buf.WriteByte('|')
+                       }
+                       name := http2flagName[h.Type][http2Flags(1<<i)]
+                       if name != "" {
+                               buf.WriteString(name)
+                       } else {
+                               fmt.Fprintf(buf, "0x%x", 1<<i)
+                       }
+               }
+       }
+       if h.StreamID != 0 {
+               fmt.Fprintf(buf, " stream=%d", h.StreamID)
+       }
+       fmt.Fprintf(buf, " len=%d", h.Length)
+}
+
+func (h *http2FrameHeader) checkValid() {
+       if !h.valid {
+               panic("Frame accessor called on non-owned Frame")
+       }
+}
+
+func (h *http2FrameHeader) invalidate() { h.valid = false }
+
+// frame header bytes.
+// Used only by ReadFrameHeader.
+var http2fhBytes = sync.Pool{
+       New: func() interface{} {
+               buf := make([]byte, http2frameHeaderLen)
+               return &buf
+       },
+}
+
+// ReadFrameHeader reads 9 bytes from r and returns a FrameHeader.
+// Most users should use Framer.ReadFrame instead.
+func http2ReadFrameHeader(r io.Reader) (http2FrameHeader, error) {
+       bufp := http2fhBytes.Get().(*[]byte)
+       defer http2fhBytes.Put(bufp)
+       return http2readFrameHeader(*bufp, r)
+}
+
+func http2readFrameHeader(buf []byte, r io.Reader) (http2FrameHeader, error) {
+       _, err := io.ReadFull(r, buf[:http2frameHeaderLen])
+       if err != nil {
+               return http2FrameHeader{}, err
+       }
+       return http2FrameHeader{
+               Length:   (uint32(buf[0])<<16 | uint32(buf[1])<<8 | uint32(buf[2])),
+               Type:     http2FrameType(buf[3]),
+               Flags:    http2Flags(buf[4]),
+               StreamID: binary.BigEndian.Uint32(buf[5:]) & (1<<31 - 1),
+               valid:    true,
+       }, nil
+}
+
+// A Frame is the base interface implemented by all frame types.
+// Callers will generally type-assert the specific frame type:
+// *HeadersFrame, *SettingsFrame, *WindowUpdateFrame, etc.
+//
+// Frames are only valid until the next call to Framer.ReadFrame.
+type http2Frame interface {
+       Header() http2FrameHeader
+
+       // invalidate is called by Framer.ReadFrame to make this
+       // frame's buffers as being invalid, since the subsequent
+       // frame will reuse them.
+       invalidate()
+}
+
+// A Framer reads and writes Frames.
+type http2Framer struct {
+       r         io.Reader
+       lastFrame http2Frame
+       errReason string
+
+       // lastHeaderStream is non-zero if the last frame was an
+       // unfinished HEADERS/CONTINUATION.
+       lastHeaderStream uint32
+
+       maxReadSize uint32
+       headerBuf   [http2frameHeaderLen]byte
+
+       // TODO: let getReadBuf be configurable, and use a less memory-pinning
+       // allocator in server.go to minimize memory pinned for many idle conns.
+       // Will probably also need to make frame invalidation have a hook too.
+       getReadBuf func(size uint32) []byte
+       readBuf    []byte // cache for default getReadBuf
+
+       maxWriteSize uint32 // zero means unlimited; TODO: implement
+
+       w    io.Writer
+       wbuf []byte
+
+       // AllowIllegalWrites permits the Framer's Write methods to
+       // write frames that do not conform to the HTTP/2 spec. This
+       // permits using the Framer to test other HTTP/2
+       // implementations' conformance to the spec.
+       // If false, the Write methods will prefer to return an error
+       // rather than comply.
+       AllowIllegalWrites bool
+
+       // AllowIllegalReads permits the Framer's ReadFrame method
+       // to return non-compliant frames or frame orders.
+       // This is for testing and permits using the Framer to test
+       // other HTTP/2 implementations' conformance to the spec.
+       AllowIllegalReads bool
+
+       logReads bool
+
+       debugFramer    *http2Framer // only use for logging written writes
+       debugFramerBuf *bytes.Buffer
+}
+
+func (f *http2Framer) startWrite(ftype http2FrameType, flags http2Flags, streamID uint32) {
+
+       f.wbuf = append(f.wbuf[:0],
+               0,
+               0,
+               0,
+               byte(ftype),
+               byte(flags),
+               byte(streamID>>24),
+               byte(streamID>>16),
+               byte(streamID>>8),
+               byte(streamID))
+}
+
+func (f *http2Framer) endWrite() error {
+
+       length := len(f.wbuf) - http2frameHeaderLen
+       if length >= (1 << 24) {
+               return http2ErrFrameTooLarge
+       }
+       _ = append(f.wbuf[:0],
+               byte(length>>16),
+               byte(length>>8),
+               byte(length))
+       if http2logFrameWrites {
+               f.logWrite()
+       }
+
+       n, err := f.w.Write(f.wbuf)
+       if err == nil && n != len(f.wbuf) {
+               err = io.ErrShortWrite
+       }
+       return err
+}
+
+func (f *http2Framer) logWrite() {
+       if f.debugFramer == nil {
+               f.debugFramerBuf = new(bytes.Buffer)
+               f.debugFramer = http2NewFramer(nil, f.debugFramerBuf)
+               f.debugFramer.logReads = false
+
+               f.debugFramer.AllowIllegalReads = true
+       }
+       f.debugFramerBuf.Write(f.wbuf)
+       fr, err := f.debugFramer.ReadFrame()
+       if err != nil {
+               log.Printf("http2: Framer %p: failed to decode just-written frame", f)
+               return
+       }
+       log.Printf("http2: Framer %p: wrote %v", f, http2summarizeFrame(fr))
+}
+
+func (f *http2Framer) writeByte(v byte) { f.wbuf = append(f.wbuf, v) }
+
+func (f *http2Framer) writeBytes(v []byte) { f.wbuf = append(f.wbuf, v...) }
+
+func (f *http2Framer) writeUint16(v uint16) { f.wbuf = append(f.wbuf, byte(v>>8), byte(v)) }
+
+func (f *http2Framer) writeUint32(v uint32) {
+       f.wbuf = append(f.wbuf, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
+}
+
+const (
+       http2minMaxFrameSize = 1 << 14
+       http2maxFrameSize    = 1<<24 - 1
+)
+
+// NewFramer returns a Framer that writes frames to w and reads them from r.
+func http2NewFramer(w io.Writer, r io.Reader) *http2Framer {
+       fr := &http2Framer{
+               w:        w,
+               r:        r,
+               logReads: http2logFrameReads,
+       }
+       fr.getReadBuf = func(size uint32) []byte {
+               if cap(fr.readBuf) >= int(size) {
+                       return fr.readBuf[:size]
+               }
+               fr.readBuf = make([]byte, size)
+               return fr.readBuf
+       }
+       fr.SetMaxReadFrameSize(http2maxFrameSize)
+       return fr
+}
+
+// SetMaxReadFrameSize sets the maximum size of a frame
+// that will be read by a subsequent call to ReadFrame.
+// It is the caller's responsibility to advertise this
+// limit with a SETTINGS frame.
+func (fr *http2Framer) SetMaxReadFrameSize(v uint32) {
+       if v > http2maxFrameSize {
+               v = http2maxFrameSize
+       }
+       fr.maxReadSize = v
+}
+
+// ErrFrameTooLarge is returned from Framer.ReadFrame when the peer
+// sends a frame that is larger than declared with SetMaxReadFrameSize.
+var http2ErrFrameTooLarge = errors.New("http2: frame too large")
+
+// terminalReadFrameError reports whether err is an unrecoverable
+// error from ReadFrame and no other frames should be read.
+func http2terminalReadFrameError(err error) bool {
+       if _, ok := err.(http2StreamError); ok {
+               return false
+       }
+       return err != nil
+}
+
+// ReadFrame reads a single frame. The returned Frame is only valid
+// until the next call to ReadFrame.
+//
+// If the frame is larger than previously set with SetMaxReadFrameSize, the
+// returned error is ErrFrameTooLarge. Other errors may be of type
+// ConnectionError, StreamError, or anything else from from the underlying
+// reader.
+func (fr *http2Framer) ReadFrame() (http2Frame, error) {
+       if fr.lastFrame != nil {
+               fr.lastFrame.invalidate()
+       }
+       fh, err := http2readFrameHeader(fr.headerBuf[:], fr.r)
+       if err != nil {
+               return nil, err
+       }
+       if fh.Length > fr.maxReadSize {
+               return nil, http2ErrFrameTooLarge
+       }
+       payload := fr.getReadBuf(fh.Length)
+       if _, err := io.ReadFull(fr.r, payload); err != nil {
+               return nil, err
+       }
+       f, err := http2typeFrameParser(fh.Type)(fh, payload)
+       if err != nil {
+               if ce, ok := err.(http2connError); ok {
+                       return nil, fr.connError(ce.Code, ce.Reason)
+               }
+               return nil, err
+       }
+       if err := fr.checkFrameOrder(f); err != nil {
+               return nil, err
+       }
+       if fr.logReads {
+               log.Printf("http2: Framer %p: read %v", fr, http2summarizeFrame(f))
+       }
+       return f, nil
+}
+
+// connError returns ConnectionError(code) but first
+// stashes away a public reason to the caller can optionally relay it
+// to the peer before hanging up on them. This might help others debug
+// their implementations.
+func (fr *http2Framer) connError(code http2ErrCode, reason string) error {
+       fr.errReason = reason
+       return http2ConnectionError(code)
+}
+
+// checkFrameOrder reports an error if f is an invalid frame to return
+// next from ReadFrame. Mostly it checks whether HEADERS and
+// CONTINUATION frames are contiguous.
+func (fr *http2Framer) checkFrameOrder(f http2Frame) error {
+       last := fr.lastFrame
+       fr.lastFrame = f
+       if fr.AllowIllegalReads {
+               return nil
+       }
+
+       fh := f.Header()
+       if fr.lastHeaderStream != 0 {
+               if fh.Type != http2FrameContinuation {
+                       return fr.connError(http2ErrCodeProtocol,
+                               fmt.Sprintf("got %s for stream %d; expected CONTINUATION following %s for stream %d",
+                                       fh.Type, fh.StreamID,
+                                       last.Header().Type, fr.lastHeaderStream))
+               }
+               if fh.StreamID != fr.lastHeaderStream {
+                       return fr.connError(http2ErrCodeProtocol,
+                               fmt.Sprintf("got CONTINUATION for stream %d; expected stream %d",
+                                       fh.StreamID, fr.lastHeaderStream))
+               }
+       } else if fh.Type == http2FrameContinuation {
+               return fr.connError(http2ErrCodeProtocol, fmt.Sprintf("unexpected CONTINUATION for stream %d", fh.StreamID))
+       }
+
+       switch fh.Type {
+       case http2FrameHeaders, http2FrameContinuation:
+               if fh.Flags.Has(http2FlagHeadersEndHeaders) {
+                       fr.lastHeaderStream = 0
+               } else {
+                       fr.lastHeaderStream = fh.StreamID
+               }
+       }
+
+       return nil
+}
+
+// A DataFrame conveys arbitrary, variable-length sequences of octets
+// associated with a stream.
+// See http://http2.github.io/http2-spec/#rfc.section.6.1
+type http2DataFrame struct {
+       http2FrameHeader
+       data []byte
+}
+
+func (f *http2DataFrame) StreamEnded() bool {
+       return f.http2FrameHeader.Flags.Has(http2FlagDataEndStream)
+}
+
+// Data returns the frame's data octets, not including any padding
+// size byte or padding suffix bytes.
+// The caller must not retain the returned memory past the next
+// call to ReadFrame.
+func (f *http2DataFrame) Data() []byte {
+       f.checkValid()
+       return f.data
+}
+
+func http2parseDataFrame(fh http2FrameHeader, payload []byte) (http2Frame, error) {
+       if fh.StreamID == 0 {
+
+               return nil, http2connError{http2ErrCodeProtocol, "DATA frame with stream ID 0"}
+       }
+       f := &http2DataFrame{
+               http2FrameHeader: fh,
+       }
+       var padSize byte
+       if fh.Flags.Has(http2FlagDataPadded) {
+               var err error
+               payload, padSize, err = http2readByte(payload)
+               if err != nil {
+                       return nil, err
+               }
+       }
+       if int(padSize) > len(payload) {
+
+               return nil, http2connError{http2ErrCodeProtocol, "pad size larger than data payload"}
+       }
+       f.data = payload[:len(payload)-int(padSize)]
+       return f, nil
+}
+
+var http2errStreamID = errors.New("invalid streamid")
+
+func http2validStreamID(streamID uint32) bool {
+       return streamID != 0 && streamID&(1<<31) == 0
+}
+
+// WriteData writes a DATA frame.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility to not call other Write methods concurrently.
+func (f *http2Framer) WriteData(streamID uint32, endStream bool, data []byte) error {
+
+       if !http2validStreamID(streamID) && !f.AllowIllegalWrites {
+               return http2errStreamID
+       }
+       var flags http2Flags
+       if endStream {
+               flags |= http2FlagDataEndStream
+       }
+       f.startWrite(http2FrameData, flags, streamID)
+       f.wbuf = append(f.wbuf, data...)
+       return f.endWrite()
+}
+
+// A SettingsFrame conveys configuration parameters that affect how
+// endpoints communicate, such as preferences and constraints on peer
+// behavior.
+//
+// See http://http2.github.io/http2-spec/#SETTINGS
+type http2SettingsFrame struct {
+       http2FrameHeader
+       p []byte
+}
+
+func http2parseSettingsFrame(fh http2FrameHeader, p []byte) (http2Frame, error) {
+       if fh.Flags.Has(http2FlagSettingsAck) && fh.Length > 0 {
+
+               return nil, http2ConnectionError(http2ErrCodeFrameSize)
+       }
+       if fh.StreamID != 0 {
+
+               return nil, http2ConnectionError(http2ErrCodeProtocol)
+       }
+       if len(p)%6 != 0 {
+
+               return nil, http2ConnectionError(http2ErrCodeFrameSize)
+       }
+       f := &http2SettingsFrame{http2FrameHeader: fh, p: p}
+       if v, ok := f.Value(http2SettingInitialWindowSize); ok && v > (1<<31)-1 {
+
+               return nil, http2ConnectionError(http2ErrCodeFlowControl)
+       }
+       return f, nil
+}
+
+func (f *http2SettingsFrame) IsAck() bool {
+       return f.http2FrameHeader.Flags.Has(http2FlagSettingsAck)
+}
+
+func (f *http2SettingsFrame) Value(s http2SettingID) (v uint32, ok bool) {
+       f.checkValid()
+       buf := f.p
+       for len(buf) > 0 {
+               settingID := http2SettingID(binary.BigEndian.Uint16(buf[:2]))
+               if settingID == s {
+                       return binary.BigEndian.Uint32(buf[2:6]), true
+               }
+               buf = buf[6:]
+       }
+       return 0, false
+}
+
+// ForeachSetting runs fn for each setting.
+// It stops and returns the first error.
+func (f *http2SettingsFrame) ForeachSetting(fn func(http2Setting) error) error {
+       f.checkValid()
+       buf := f.p
+       for len(buf) > 0 {
+               if err := fn(http2Setting{
+                       http2SettingID(binary.BigEndian.Uint16(buf[:2])),
+                       binary.BigEndian.Uint32(buf[2:6]),
+               }); err != nil {
+                       return err
+               }
+               buf = buf[6:]
+       }
+       return nil
+}
+
+// WriteSettings writes a SETTINGS frame with zero or more settings
+// specified and the ACK bit not set.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility to not call other Write methods concurrently.
+func (f *http2Framer) WriteSettings(settings ...http2Setting) error {
+       f.startWrite(http2FrameSettings, 0, 0)
+       for _, s := range settings {
+               f.writeUint16(uint16(s.ID))
+               f.writeUint32(s.Val)
+       }
+       return f.endWrite()
+}
+
+// WriteSettings writes an empty SETTINGS frame with the ACK bit set.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility to not call other Write methods concurrently.
+func (f *http2Framer) WriteSettingsAck() error {
+       f.startWrite(http2FrameSettings, http2FlagSettingsAck, 0)
+       return f.endWrite()
+}
+
+// A PingFrame is a mechanism for measuring a minimal round trip time
+// from the sender, as well as determining whether an idle connection
+// is still functional.
+// See http://http2.github.io/http2-spec/#rfc.section.6.7
+type http2PingFrame struct {
+       http2FrameHeader
+       Data [8]byte
+}
+
+func (f *http2PingFrame) IsAck() bool { return f.Flags.Has(http2FlagPingAck) }
+
+func http2parsePingFrame(fh http2FrameHeader, payload []byte) (http2Frame, error) {
+       if len(payload) != 8 {
+               return nil, http2ConnectionError(http2ErrCodeFrameSize)
+       }
+       if fh.StreamID != 0 {
+               return nil, http2ConnectionError(http2ErrCodeProtocol)
+       }
+       f := &http2PingFrame{http2FrameHeader: fh}
+       copy(f.Data[:], payload)
+       return f, nil
+}
+
+func (f *http2Framer) WritePing(ack bool, data [8]byte) error {
+       var flags http2Flags
+       if ack {
+               flags = http2FlagPingAck
+       }
+       f.startWrite(http2FramePing, flags, 0)
+       f.writeBytes(data[:])
+       return f.endWrite()
+}
+
+// A GoAwayFrame informs the remote peer to stop creating streams on this connection.
+// See http://http2.github.io/http2-spec/#rfc.section.6.8
+type http2GoAwayFrame struct {
+       http2FrameHeader
+       LastStreamID uint32
+       ErrCode      http2ErrCode
+       debugData    []byte
+}
+
+// DebugData returns any debug data in the GOAWAY frame. Its contents
+// are not defined.
+// The caller must not retain the returned memory past the next
+// call to ReadFrame.
+func (f *http2GoAwayFrame) DebugData() []byte {
+       f.checkValid()
+       return f.debugData
+}
+
+func http2parseGoAwayFrame(fh http2FrameHeader, p []byte) (http2Frame, error) {
+       if fh.StreamID != 0 {
+               return nil, http2ConnectionError(http2ErrCodeProtocol)
+       }
+       if len(p) < 8 {
+               return nil, http2ConnectionError(http2ErrCodeFrameSize)
+       }
+       return &http2GoAwayFrame{
+               http2FrameHeader: fh,
+               LastStreamID:     binary.BigEndian.Uint32(p[:4]) & (1<<31 - 1),
+               ErrCode:          http2ErrCode(binary.BigEndian.Uint32(p[4:8])),
+               debugData:        p[8:],
+       }, nil
+}
+
+func (f *http2Framer) WriteGoAway(maxStreamID uint32, code http2ErrCode, debugData []byte) error {
+       f.startWrite(http2FrameGoAway, 0, 0)
+       f.writeUint32(maxStreamID & (1<<31 - 1))
+       f.writeUint32(uint32(code))
+       f.writeBytes(debugData)
+       return f.endWrite()
+}
+
+// An UnknownFrame is the frame type returned when the frame type is unknown
+// or no specific frame type parser exists.
+type http2UnknownFrame struct {
+       http2FrameHeader
+       p []byte
+}
+
+// Payload returns the frame's payload (after the header).  It is not
+// valid to call this method after a subsequent call to
+// Framer.ReadFrame, nor is it valid to retain the returned slice.
+// The memory is owned by the Framer and is invalidated when the next
+// frame is read.
+func (f *http2UnknownFrame) Payload() []byte {
+       f.checkValid()
+       return f.p
+}
+
+func http2parseUnknownFrame(fh http2FrameHeader, p []byte) (http2Frame, error) {
+       return &http2UnknownFrame{fh, p}, nil
+}
+
+// A WindowUpdateFrame is used to implement flow control.
+// See http://http2.github.io/http2-spec/#rfc.section.6.9
+type http2WindowUpdateFrame struct {
+       http2FrameHeader
+       Increment uint32 // never read with high bit set
+}
+
+func http2parseWindowUpdateFrame(fh http2FrameHeader, p []byte) (http2Frame, error) {
+       if len(p) != 4 {
+               return nil, http2ConnectionError(http2ErrCodeFrameSize)
+       }
+       inc := binary.BigEndian.Uint32(p[:4]) & 0x7fffffff
+       if inc == 0 {
+
+               if fh.StreamID == 0 {
+                       return nil, http2ConnectionError(http2ErrCodeProtocol)
+               }
+               return nil, http2StreamError{fh.StreamID, http2ErrCodeProtocol}
+       }
+       return &http2WindowUpdateFrame{
+               http2FrameHeader: fh,
+               Increment:        inc,
+       }, nil
+}
+
+// WriteWindowUpdate writes a WINDOW_UPDATE frame.
+// The increment value must be between 1 and 2,147,483,647, inclusive.
+// If the Stream ID is zero, the window update applies to the
+// connection as a whole.
+func (f *http2Framer) WriteWindowUpdate(streamID, incr uint32) error {
+
+       if (incr < 1 || incr > 2147483647) && !f.AllowIllegalWrites {
+               return errors.New("illegal window increment value")
+       }
+       f.startWrite(http2FrameWindowUpdate, 0, streamID)
+       f.writeUint32(incr)
+       return f.endWrite()
+}
+
+// A HeadersFrame is used to open a stream and additionally carries a
+// header block fragment.
+type http2HeadersFrame struct {
+       http2FrameHeader
+
+       // Priority is set if FlagHeadersPriority is set in the FrameHeader.
+       Priority http2PriorityParam
+
+       headerFragBuf []byte // not owned
+}
+
+func (f *http2HeadersFrame) HeaderBlockFragment() []byte {
+       f.checkValid()
+       return f.headerFragBuf
+}
+
+func (f *http2HeadersFrame) HeadersEnded() bool {
+       return f.http2FrameHeader.Flags.Has(http2FlagHeadersEndHeaders)
+}
+
+func (f *http2HeadersFrame) StreamEnded() bool {
+       return f.http2FrameHeader.Flags.Has(http2FlagHeadersEndStream)
+}
+
+func (f *http2HeadersFrame) HasPriority() bool {
+       return f.http2FrameHeader.Flags.Has(http2FlagHeadersPriority)
+}
+
+func http2parseHeadersFrame(fh http2FrameHeader, p []byte) (_ http2Frame, err error) {
+       hf := &http2HeadersFrame{
+               http2FrameHeader: fh,
+       }
+       if fh.StreamID == 0 {
+
+               return nil, http2connError{http2ErrCodeProtocol, "HEADERS frame with stream ID 0"}
+       }
+       var padLength uint8
+       if fh.Flags.Has(http2FlagHeadersPadded) {
+               if p, padLength, err = http2readByte(p); err != nil {
+                       return
+               }
+       }
+       if fh.Flags.Has(http2FlagHeadersPriority) {
+               var v uint32
+               p, v, err = http2readUint32(p)
+               if err != nil {
+                       return nil, err
+               }
+               hf.Priority.StreamDep = v & 0x7fffffff
+               hf.Priority.Exclusive = (v != hf.Priority.StreamDep)
+               p, hf.Priority.Weight, err = http2readByte(p)
+               if err != nil {
+                       return nil, err
+               }
+       }
+       if len(p)-int(padLength) <= 0 {
+               return nil, http2StreamError{fh.StreamID, http2ErrCodeProtocol}
+       }
+       hf.headerFragBuf = p[:len(p)-int(padLength)]
+       return hf, nil
+}
+
+// HeadersFrameParam are the parameters for writing a HEADERS frame.
+type http2HeadersFrameParam struct {
+       // StreamID is the required Stream ID to initiate.
+       StreamID uint32
+       // BlockFragment is part (or all) of a Header Block.
+       BlockFragment []byte
+
+       // EndStream indicates that the header block is the last that
+       // the endpoint will send for the identified stream. Setting
+       // this flag causes the stream to enter one of "half closed"
+       // states.
+       EndStream bool
+
+       // EndHeaders indicates that this frame contains an entire
+       // header block and is not followed by any
+       // CONTINUATION frames.
+       EndHeaders bool
+
+       // PadLength is the optional number of bytes of zeros to add
+       // to this frame.
+       PadLength uint8
+
+       // Priority, if non-zero, includes stream priority information
+       // in the HEADER frame.
+       Priority http2PriorityParam
+}
+
+// WriteHeaders writes a single HEADERS frame.
+//
+// This is a low-level header writing method. Encoding headers and
+// splitting them into any necessary CONTINUATION frames is handled
+// elsewhere.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility to not call other Write methods concurrently.
+func (f *http2Framer) WriteHeaders(p http2HeadersFrameParam) error {
+       if !http2validStreamID(p.StreamID) && !f.AllowIllegalWrites {
+               return http2errStreamID
+       }
+       var flags http2Flags
+       if p.PadLength != 0 {
+               flags |= http2FlagHeadersPadded
+       }
+       if p.EndStream {
+               flags |= http2FlagHeadersEndStream
+       }
+       if p.EndHeaders {
+               flags |= http2FlagHeadersEndHeaders
+       }
+       if !p.Priority.IsZero() {
+               flags |= http2FlagHeadersPriority
+       }
+       f.startWrite(http2FrameHeaders, flags, p.StreamID)
+       if p.PadLength != 0 {
+               f.writeByte(p.PadLength)
+       }
+       if !p.Priority.IsZero() {
+               v := p.Priority.StreamDep
+               if !http2validStreamID(v) && !f.AllowIllegalWrites {
+                       return errors.New("invalid dependent stream id")
+               }
+               if p.Priority.Exclusive {
+                       v |= 1 << 31
+               }
+               f.writeUint32(v)
+               f.writeByte(p.Priority.Weight)
+       }
+       f.wbuf = append(f.wbuf, p.BlockFragment...)
+       f.wbuf = append(f.wbuf, http2padZeros[:p.PadLength]...)
+       return f.endWrite()
+}
+
+// A PriorityFrame specifies the sender-advised priority of a stream.
+// See http://http2.github.io/http2-spec/#rfc.section.6.3
+type http2PriorityFrame struct {
+       http2FrameHeader
+       http2PriorityParam
+}
+
+// PriorityParam are the stream prioritzation parameters.
+type http2PriorityParam struct {
+       // StreamDep is a 31-bit stream identifier for the
+       // stream that this stream depends on. Zero means no
+       // dependency.
+       StreamDep uint32
+
+       // Exclusive is whether the dependency is exclusive.
+       Exclusive bool
+
+       // Weight is the stream's zero-indexed weight. It should be
+       // set together with StreamDep, or neither should be set.  Per
+       // the spec, "Add one to the value to obtain a weight between
+       // 1 and 256."
+       Weight uint8
+}
+
+func (p http2PriorityParam) IsZero() bool {
+       return p == http2PriorityParam{}
+}
+
+func http2parsePriorityFrame(fh http2FrameHeader, payload []byte) (http2Frame, error) {
+       if fh.StreamID == 0 {
+               return nil, http2connError{http2ErrCodeProtocol, "PRIORITY frame with stream ID 0"}
+       }
+       if len(payload) != 5 {
+               return nil, http2connError{http2ErrCodeFrameSize, fmt.Sprintf("PRIORITY frame payload size was %d; want 5", len(payload))}
+       }
+       v := binary.BigEndian.Uint32(payload[:4])
+       streamID := v & 0x7fffffff
+       return &http2PriorityFrame{
+               http2FrameHeader: fh,
+               http2PriorityParam: http2PriorityParam{
+                       Weight:    payload[4],
+                       StreamDep: streamID,
+                       Exclusive: streamID != v,
+               },
+       }, nil
+}
+
+// WritePriority writes a PRIORITY frame.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility to not call other Write methods concurrently.
+func (f *http2Framer) WritePriority(streamID uint32, p http2PriorityParam) error {
+       if !http2validStreamID(streamID) && !f.AllowIllegalWrites {
+               return http2errStreamID
+       }
+       f.startWrite(http2FramePriority, 0, streamID)
+       v := p.StreamDep
+       if p.Exclusive {
+               v |= 1 << 31
+       }
+       f.writeUint32(v)
+       f.writeByte(p.Weight)
+       return f.endWrite()
+}
+
+// A RSTStreamFrame allows for abnormal termination of a stream.
+// See http://http2.github.io/http2-spec/#rfc.section.6.4
+type http2RSTStreamFrame struct {
+       http2FrameHeader
+       ErrCode http2ErrCode
+}
+
+func http2parseRSTStreamFrame(fh http2FrameHeader, p []byte) (http2Frame, error) {
+       if len(p) != 4 {
+               return nil, http2ConnectionError(http2ErrCodeFrameSize)
+       }
+       if fh.StreamID == 0 {
+               return nil, http2ConnectionError(http2ErrCodeProtocol)
+       }
+       return &http2RSTStreamFrame{fh, http2ErrCode(binary.BigEndian.Uint32(p[:4]))}, nil
+}
+
+// WriteRSTStream writes a RST_STREAM frame.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility to not call other Write methods concurrently.
+func (f *http2Framer) WriteRSTStream(streamID uint32, code http2ErrCode) error {
+       if !http2validStreamID(streamID) && !f.AllowIllegalWrites {
+               return http2errStreamID
+       }
+       f.startWrite(http2FrameRSTStream, 0, streamID)
+       f.writeUint32(uint32(code))
+       return f.endWrite()
+}
+
+// A ContinuationFrame is used to continue a sequence of header block fragments.
+// See http://http2.github.io/http2-spec/#rfc.section.6.10
+type http2ContinuationFrame struct {
+       http2FrameHeader
+       headerFragBuf []byte
+}
+
+func http2parseContinuationFrame(fh http2FrameHeader, p []byte) (http2Frame, error) {
+       if fh.StreamID == 0 {
+               return nil, http2connError{http2ErrCodeProtocol, "CONTINUATION frame with stream ID 0"}
+       }
+       return &http2ContinuationFrame{fh, p}, nil
+}
+
+func (f *http2ContinuationFrame) HeaderBlockFragment() []byte {
+       f.checkValid()
+       return f.headerFragBuf
+}
+
+func (f *http2ContinuationFrame) HeadersEnded() bool {
+       return f.http2FrameHeader.Flags.Has(http2FlagContinuationEndHeaders)
+}
+
+// WriteContinuation writes a CONTINUATION frame.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility to not call other Write methods concurrently.
+func (f *http2Framer) WriteContinuation(streamID uint32, endHeaders bool, headerBlockFragment []byte) error {
+       if !http2validStreamID(streamID) && !f.AllowIllegalWrites {
+               return http2errStreamID
+       }
+       var flags http2Flags
+       if endHeaders {
+               flags |= http2FlagContinuationEndHeaders
+       }
+       f.startWrite(http2FrameContinuation, flags, streamID)
+       f.wbuf = append(f.wbuf, headerBlockFragment...)
+       return f.endWrite()
+}
+
+// A PushPromiseFrame is used to initiate a server stream.
+// See http://http2.github.io/http2-spec/#rfc.section.6.6
+type http2PushPromiseFrame struct {
+       http2FrameHeader
+       PromiseID     uint32
+       headerFragBuf []byte // not owned
+}
+
+func (f *http2PushPromiseFrame) HeaderBlockFragment() []byte {
+       f.checkValid()
+       return f.headerFragBuf
+}
+
+func (f *http2PushPromiseFrame) HeadersEnded() bool {
+       return f.http2FrameHeader.Flags.Has(http2FlagPushPromiseEndHeaders)
+}
+
+func http2parsePushPromise(fh http2FrameHeader, p []byte) (_ http2Frame, err error) {
+       pp := &http2PushPromiseFrame{
+               http2FrameHeader: fh,
+       }
+       if pp.StreamID == 0 {
+
+               return nil, http2ConnectionError(http2ErrCodeProtocol)
+       }
+       // The PUSH_PROMISE frame includes optional padding.
+       // Padding fields and flags are identical to those defined for DATA frames
+       var padLength uint8
+       if fh.Flags.Has(http2FlagPushPromisePadded) {
+               if p, padLength, err = http2readByte(p); err != nil {
+                       return
+               }
+       }
+
+       p, pp.PromiseID, err = http2readUint32(p)
+       if err != nil {
+               return
+       }
+       pp.PromiseID = pp.PromiseID & (1<<31 - 1)
+
+       if int(padLength) > len(p) {
+
+               return nil, http2ConnectionError(http2ErrCodeProtocol)
+       }
+       pp.headerFragBuf = p[:len(p)-int(padLength)]
+       return pp, nil
+}
+
+// PushPromiseParam are the parameters for writing a PUSH_PROMISE frame.
+type http2PushPromiseParam struct {
+       // StreamID is the required Stream ID to initiate.
+       StreamID uint32
+
+       // PromiseID is the required Stream ID which this
+       // Push Promises
+       PromiseID uint32
+
+       // BlockFragment is part (or all) of a Header Block.
+       BlockFragment []byte
+
+       // EndHeaders indicates that this frame contains an entire
+       // header block and is not followed by any
+       // CONTINUATION frames.
+       EndHeaders bool
+
+       // PadLength is the optional number of bytes of zeros to add
+       // to this frame.
+       PadLength uint8
+}
+
+// WritePushPromise writes a single PushPromise Frame.
+//
+// As with Header Frames, This is the low level call for writing
+// individual frames. Continuation frames are handled elsewhere.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility to not call other Write methods concurrently.
+func (f *http2Framer) WritePushPromise(p http2PushPromiseParam) error {
+       if !http2validStreamID(p.StreamID) && !f.AllowIllegalWrites {
+               return http2errStreamID
+       }
+       var flags http2Flags
+       if p.PadLength != 0 {
+               flags |= http2FlagPushPromisePadded
+       }
+       if p.EndHeaders {
+               flags |= http2FlagPushPromiseEndHeaders
+       }
+       f.startWrite(http2FramePushPromise, flags, p.StreamID)
+       if p.PadLength != 0 {
+               f.writeByte(p.PadLength)
+       }
+       if !http2validStreamID(p.PromiseID) && !f.AllowIllegalWrites {
+               return http2errStreamID
+       }
+       f.writeUint32(p.PromiseID)
+       f.wbuf = append(f.wbuf, p.BlockFragment...)
+       f.wbuf = append(f.wbuf, http2padZeros[:p.PadLength]...)
+       return f.endWrite()
+}
+
+// WriteRawFrame writes a raw frame. This can be used to write
+// extension frames unknown to this package.
+func (f *http2Framer) WriteRawFrame(t http2FrameType, flags http2Flags, streamID uint32, payload []byte) error {
+       f.startWrite(t, flags, streamID)
+       f.writeBytes(payload)
+       return f.endWrite()
+}
+
+func http2readByte(p []byte) (remain []byte, b byte, err error) {
+       if len(p) == 0 {
+               return nil, 0, io.ErrUnexpectedEOF
+       }
+       return p[1:], p[0], nil
+}
+
+func http2readUint32(p []byte) (remain []byte, v uint32, err error) {
+       if len(p) < 4 {
+               return nil, 0, io.ErrUnexpectedEOF
+       }
+       return p[4:], binary.BigEndian.Uint32(p[:4]), nil
+}
+
+type http2streamEnder interface {
+       StreamEnded() bool
+}
+
+type http2headersEnder interface {
+       HeadersEnded() bool
+}
+
+func http2summarizeFrame(f http2Frame) string {
+       var buf bytes.Buffer
+       f.Header().writeDebug(&buf)
+       switch f := f.(type) {
+       case *http2SettingsFrame:
+               n := 0
+               f.ForeachSetting(func(s http2Setting) error {
+                       n++
+                       if n == 1 {
+                               buf.WriteString(", settings:")
+                       }
+                       fmt.Fprintf(&buf, " %v=%v,", s.ID, s.Val)
+                       return nil
+               })
+               if n > 0 {
+                       buf.Truncate(buf.Len() - 1)
+               }
+       case *http2DataFrame:
+               data := f.Data()
+               const max = 256
+               if len(data) > max {
+                       data = data[:max]
+               }
+               fmt.Fprintf(&buf, " data=%q", data)
+               if len(f.Data()) > max {
+                       fmt.Fprintf(&buf, " (%d bytes omitted)", len(f.Data())-max)
+               }
+       case *http2WindowUpdateFrame:
+               if f.StreamID == 0 {
+                       buf.WriteString(" (conn)")
+               }
+               fmt.Fprintf(&buf, " incr=%v", f.Increment)
+       case *http2PingFrame:
+               fmt.Fprintf(&buf, " ping=%q", f.Data[:])
+       case *http2GoAwayFrame:
+               fmt.Fprintf(&buf, " LastStreamID=%v ErrCode=%v Debug=%q",
+                       f.LastStreamID, f.ErrCode, f.debugData)
+       case *http2RSTStreamFrame:
+               fmt.Fprintf(&buf, " ErrCode=%v", f.ErrCode)
+       }
+       return buf.String()
+}
+
+func http2requestCancel(req *Request) <-chan struct{} { return req.Cancel }
+
+var http2DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"
+
+type http2goroutineLock uint64
+
+func http2newGoroutineLock() http2goroutineLock {
+       if !http2DebugGoroutines {
+               return 0
+       }
+       return http2goroutineLock(http2curGoroutineID())
+}
+
+func (g http2goroutineLock) check() {
+       if !http2DebugGoroutines {
+               return
+       }
+       if http2curGoroutineID() != uint64(g) {
+               panic("running on the wrong goroutine")
+       }
+}
+
+func (g http2goroutineLock) checkNotOn() {
+       if !http2DebugGoroutines {
+               return
+       }
+       if http2curGoroutineID() == uint64(g) {
+               panic("running on the wrong goroutine")
+       }
+}
+
+var http2goroutineSpace = []byte("goroutine ")
+
+func http2curGoroutineID() uint64 {
+       bp := http2littleBuf.Get().(*[]byte)
+       defer http2littleBuf.Put(bp)
+       b := *bp
+       b = b[:runtime.Stack(b, false)]
+
+       b = bytes.TrimPrefix(b, http2goroutineSpace)
+       i := bytes.IndexByte(b, ' ')
+       if i < 0 {
+               panic(fmt.Sprintf("No space found in %q", b))
+       }
+       b = b[:i]
+       n, err := http2parseUintBytes(b, 10, 64)
+       if err != nil {
+               panic(fmt.Sprintf("Failed to parse goroutine ID out of %q: %v", b, err))
+       }
+       return n
+}
+
+var http2littleBuf = sync.Pool{
+       New: func() interface{} {
+               buf := make([]byte, 64)
+               return &buf
+       },
+}
+
+// parseUintBytes is like strconv.ParseUint, but using a []byte.
+func http2parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) {
+       var cutoff, maxVal uint64
+
+       if bitSize == 0 {
+               bitSize = int(strconv.IntSize)
+       }
+
+       s0 := s
+       switch {
+       case len(s) < 1:
+               err = strconv.ErrSyntax
+               goto Error
+
+       case 2 <= base && base <= 36:
+
+       case base == 0:
+
+               switch {
+               case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
+                       base = 16
+                       s = s[2:]
+                       if len(s) < 1 {
+                               err = strconv.ErrSyntax
+                               goto Error
+                       }
+               case s[0] == '0':
+                       base = 8
+               default:
+                       base = 10
+               }
+
+       default:
+               err = errors.New("invalid base " + strconv.Itoa(base))
+               goto Error
+       }
+
+       n = 0
+       cutoff = http2cutoff64(base)
+       maxVal = 1<<uint(bitSize) - 1
+
+       for i := 0; i < len(s); i++ {
+               var v byte
+               d := s[i]
+               switch {
+               case '0' <= d && d <= '9':
+                       v = d - '0'
+               case 'a' <= d && d <= 'z':
+                       v = d - 'a' + 10
+               case 'A' <= d && d <= 'Z':
+                       v = d - 'A' + 10
+               default:
+                       n = 0
+                       err = strconv.ErrSyntax
+                       goto Error
+               }
+               if int(v) >= base {
+                       n = 0
+                       err = strconv.ErrSyntax
+                       goto Error
+               }
+
+               if n >= cutoff {
+
+                       n = 1<<64 - 1
+                       err = strconv.ErrRange
+                       goto Error
+               }
+               n *= uint64(base)
+
+               n1 := n + uint64(v)
+               if n1 < n || n1 > maxVal {
+
+                       n = 1<<64 - 1
+                       err = strconv.ErrRange
+                       goto Error
+               }
+               n = n1
+       }
+
+       return n, nil
+
+Error:
+       return n, &strconv.NumError{Func: "ParseUint", Num: string(s0), Err: err}
+}
+
+// Return the first number n such that n*base >= 1<<64.
+func http2cutoff64(base int) uint64 {
+       if base < 2 {
+               return 0
+       }
+       return (1<<64-1)/uint64(base) + 1
+}
+
+var (
+       http2commonLowerHeader = map[string]string{} // Go-Canonical-Case -> lower-case
+       http2commonCanonHeader = map[string]string{} // lower-case -> Go-Canonical-Case
+)
+
+func init() {
+       for _, v := range []string{
+               "accept",
+               "accept-charset",
+               "accept-encoding",
+               "accept-language",
+               "accept-ranges",
+               "age",
+               "access-control-allow-origin",
+               "allow",
+               "authorization",
+               "cache-control",
+               "content-disposition",
+               "content-encoding",
+               "content-language",
+               "content-length",
+               "content-location",
+               "content-range",
+               "content-type",
+               "cookie",
+               "date",
+               "etag",
+               "expect",
+               "expires",
+               "from",
+               "host",
+               "if-match",
+               "if-modified-since",
+               "if-none-match",
+               "if-unmodified-since",
+               "last-modified",
+               "link",
+               "location",
+               "max-forwards",
+               "proxy-authenticate",
+               "proxy-authorization",
+               "range",
+               "referer",
+               "refresh",
+               "retry-after",
+               "server",
+               "set-cookie",
+               "strict-transport-security",
+               "trailer",
+               "transfer-encoding",
+               "user-agent",
+               "vary",
+               "via",
+               "www-authenticate",
+       } {
+               chk := CanonicalHeaderKey(v)
+               http2commonLowerHeader[chk] = v
+               http2commonCanonHeader[v] = chk
+       }
+}
+
+func http2lowerHeader(v string) string {
+       if s, ok := http2commonLowerHeader[v]; ok {
+               return s
+       }
+       return strings.ToLower(v)
+}
+
+var (
+       http2VerboseLogs    bool
+       http2logFrameWrites bool
+       http2logFrameReads  bool
+)
+
+func init() {
+       e := os.Getenv("GODEBUG")
+       if strings.Contains(e, "http2debug=1") {
+               http2VerboseLogs = true
+       }
+       if strings.Contains(e, "http2debug=2") {
+               http2VerboseLogs = true
+               http2logFrameWrites = true
+               http2logFrameReads = true
+       }
+}
+
+const (
+       // ClientPreface is the string that must be sent by new
+       // connections from clients.
+       http2ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
+
+       // SETTINGS_MAX_FRAME_SIZE default
+       // http://http2.github.io/http2-spec/#rfc.section.6.5.2
+       http2initialMaxFrameSize = 16384
+
+       // NextProtoTLS is the NPN/ALPN protocol negotiated during
+       // HTTP/2's TLS setup.
+       http2NextProtoTLS = "h2"
+
+       // http://http2.github.io/http2-spec/#SettingValues
+       http2initialHeaderTableSize = 4096
+
+       http2initialWindowSize = 65535 // 6.9.2 Initial Flow Control Window Size
+
+       http2defaultMaxReadFrameSize = 1 << 20
+)
+
+var (
+       http2clientPreface = []byte(http2ClientPreface)
+)
+
+type http2streamState int
+
+const (
+       http2stateIdle http2streamState = iota
+       http2stateOpen
+       http2stateHalfClosedLocal
+       http2stateHalfClosedRemote
+       http2stateResvLocal
+       http2stateResvRemote
+       http2stateClosed
+)
+
+var http2stateName = [...]string{
+       http2stateIdle:             "Idle",
+       http2stateOpen:             "Open",
+       http2stateHalfClosedLocal:  "HalfClosedLocal",
+       http2stateHalfClosedRemote: "HalfClosedRemote",
+       http2stateResvLocal:        "ResvLocal",
+       http2stateResvRemote:       "ResvRemote",
+       http2stateClosed:           "Closed",
+}
+
+func (st http2streamState) String() string {
+       return http2stateName[st]
+}
+
+// Setting is a setting parameter: which setting it is, and its value.
+type http2Setting struct {
+       // ID is which setting is being set.
+       // See http://http2.github.io/http2-spec/#SettingValues
+       ID http2SettingID
+
+       // Val is the value.
+       Val uint32
+}
+
+func (s http2Setting) String() string {
+       return fmt.Sprintf("[%v = %d]", s.ID, s.Val)
+}
+
+// Valid reports whether the setting is valid.
+func (s http2Setting) Valid() error {
+
+       switch s.ID {
+       case http2SettingEnablePush:
+               if s.Val != 1 && s.Val != 0 {
+                       return http2ConnectionError(http2ErrCodeProtocol)
+               }
+       case http2SettingInitialWindowSize:
+               if s.Val > 1<<31-1 {
+                       return http2ConnectionError(http2ErrCodeFlowControl)
+               }
+       case http2SettingMaxFrameSize:
+               if s.Val < 16384 || s.Val > 1<<24-1 {
+                       return http2ConnectionError(http2ErrCodeProtocol)
+               }
+       }
+       return nil
+}
+
+// A SettingID is an HTTP/2 setting as defined in
+// http://http2.github.io/http2-spec/#iana-settings
+type http2SettingID uint16
+
+const (
+       http2SettingHeaderTableSize      http2SettingID = 0x1
+       http2SettingEnablePush           http2SettingID = 0x2
+       http2SettingMaxConcurrentStreams http2SettingID = 0x3
+       http2SettingInitialWindowSize    http2SettingID = 0x4
+       http2SettingMaxFrameSize         http2SettingID = 0x5
+       http2SettingMaxHeaderListSize    http2SettingID = 0x6
+)
+
+var http2settingName = map[http2SettingID]string{
+       http2SettingHeaderTableSize:      "HEADER_TABLE_SIZE",
+       http2SettingEnablePush:           "ENABLE_PUSH",
+       http2SettingMaxConcurrentStreams: "MAX_CONCURRENT_STREAMS",
+       http2SettingInitialWindowSize:    "INITIAL_WINDOW_SIZE",
+       http2SettingMaxFrameSize:         "MAX_FRAME_SIZE",
+       http2SettingMaxHeaderListSize:    "MAX_HEADER_LIST_SIZE",
+}
+
+func (s http2SettingID) String() string {
+       if v, ok := http2settingName[s]; ok {
+               return v
+       }
+       return fmt.Sprintf("UNKNOWN_SETTING_%d", uint16(s))
+}
+
+var (
+       http2errInvalidHeaderFieldName  = errors.New("http2: invalid header field name")
+       http2errInvalidHeaderFieldValue = errors.New("http2: invalid header field value")
+)
+
+// validHeaderFieldName reports whether v is a valid header field name (key).
+//  RFC 7230 says:
+//   header-field   = field-name ":" OWS field-value OWS
+//   field-name     = token
+//   tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
+//           "^" / "_" / "
+// Further, http2 says:
+//   "Just as in HTTP/1.x, header field names are strings of ASCII
+//   characters that are compared in a case-insensitive
+//   fashion. However, header field names MUST be converted to
+//   lowercase prior to their encoding in HTTP/2. "
+func http2validHeaderFieldName(v string) bool {
+       if len(v) == 0 {
+               return false
+       }
+       for _, r := range v {
+               if int(r) >= len(http2isTokenTable) || ('A' <= r && r <= 'Z') {
+                       return false
+               }
+               if !http2isTokenTable[byte(r)] {
+                       return false
+               }
+       }
+       return true
+}
+
+// validHeaderFieldValue reports whether v is a valid header field value.
+//
+// RFC 7230 says:
+//  field-value    = *( field-content / obs-fold )
+//  obj-fold       =  N/A to http2, and deprecated
+//  field-content  = field-vchar [ 1*( SP / HTAB ) field-vchar ]
+//  field-vchar    = VCHAR / obs-text
+//  obs-text       = %x80-FF
+//  VCHAR          = "any visible [USASCII] character"
+//
+// http2 further says: "Similarly, HTTP/2 allows header field values
+// that are not valid. While most of the values that can be encoded
+// will not alter header field parsing, carriage return (CR, ASCII
+// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII
+// 0x0) might be exploited by an attacker if they are translated
+// verbatim. Any request or response that contains a character not
+// permitted in a header field value MUST be treated as malformed
+// (Section 8.1.2.6). Valid characters are defined by the
+// field-content ABNF rule in Section 3.2 of [RFC7230]."
+//
+// This function does not (yet?) properly handle the rejection of
+// strings that begin or end with SP or HTAB.
+func http2validHeaderFieldValue(v string) bool {
+       for i := 0; i < len(v); i++ {
+               if b := v[i]; b < ' ' && b != '\t' || b == 0x7f {
+                       return false
+               }
+       }
+       return true
+}
+
+var http2httpCodeStringCommon = map[int]string{} // n -> strconv.Itoa(n)
+
+func init() {
+       for i := 100; i <= 999; i++ {
+               if v := StatusText(i); v != "" {
+                       http2httpCodeStringCommon[i] = strconv.Itoa(i)
+               }
+       }
+}
+
+func http2httpCodeString(code int) string {
+       if s, ok := http2httpCodeStringCommon[code]; ok {
+               return s
+       }
+       return strconv.Itoa(code)
+}
+
+// from pkg io
+type http2stringWriter interface {
+       WriteString(s string) (n int, err error)
+}
+
+// A gate lets two goroutines coordinate their activities.
+type http2gate chan struct{}
+
+func (g http2gate) Done() { g <- struct{}{} }
+
+func (g http2gate) Wait() { <-g }
+
+// A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed).
+type http2closeWaiter chan struct{}
+
+// Init makes a closeWaiter usable.
+// It exists because so a closeWaiter value can be placed inside a
+// larger struct and have the Mutex and Cond's memory in the same
+// allocation.
+func (cw *http2closeWaiter) Init() {
+       *cw = make(chan struct{})
+}
+
+// Close marks the closeWaiter as closed and unblocks any waiters.
+func (cw http2closeWaiter) Close() {
+       close(cw)
+}
+
+// Wait waits for the closeWaiter to become closed.
+func (cw http2closeWaiter) Wait() {
+       <-cw
+}
+
+// bufferedWriter is a buffered writer that writes to w.
+// Its buffered writer is lazily allocated as needed, to minimize
+// idle memory usage with many connections.
+type http2bufferedWriter struct {
+       w  io.Writer     // immutable
+       bw *bufio.Writer // non-nil when data is buffered
+}
+
+func http2newBufferedWriter(w io.Writer) *http2bufferedWriter {
+       return &http2bufferedWriter{w: w}
+}
+
+var http2bufWriterPool = sync.Pool{
+       New: func() interface{} {
+
+               return bufio.NewWriterSize(nil, 4<<10)
+       },
+}
+
+func (w *http2bufferedWriter) Write(p []byte) (n int, err error) {
+       if w.bw == nil {
+               bw := http2bufWriterPool.Get().(*bufio.Writer)
+               bw.Reset(w.w)
+               w.bw = bw
+       }
+       return w.bw.Write(p)
+}
+
+func (w *http2bufferedWriter) Flush() error {
+       bw := w.bw
+       if bw == nil {
+               return nil
+       }
+       err := bw.Flush()
+       bw.Reset(nil)
+       http2bufWriterPool.Put(bw)
+       w.bw = nil
+       return err
+}
+
+func http2mustUint31(v int32) uint32 {
+       if v < 0 || v > 2147483647 {
+               panic("out of range")
+       }
+       return uint32(v)
+}
+
+// bodyAllowedForStatus reports whether a given response status code
+// permits a body. See RFC2616, section 4.4.
+func http2bodyAllowedForStatus(status int) bool {
+       switch {
+       case status >= 100 && status <= 199:
+               return false
+       case status == 204:
+               return false
+       case status == 304:
+               return false
+       }
+       return true
+}
+
+type http2httpError struct {
+       msg     string
+       timeout bool
+}
+
+func (e *http2httpError) Error() string { return e.msg }
+
+func (e *http2httpError) Timeout() bool { return e.timeout }
+
+func (e *http2httpError) Temporary() bool { return true }
+
+var http2errTimeout error = &http2httpError{msg: "http2: timeout awaiting response headers", timeout: true}
+
+var http2isTokenTable = [127]bool{
+       '!':  true,
+       '#':  true,
+       '$':  true,
+       '%':  true,
+       '&':  true,
+       '\'': true,
+       '*':  true,
+       '+':  true,
+       '-':  true,
+       '.':  true,
+       '0':  true,
+       '1':  true,
+       '2':  true,
+       '3':  true,
+       '4':  true,
+       '5':  true,
+       '6':  true,
+       '7':  true,
+       '8':  true,
+       '9':  true,
+       'A':  true,
+       'B':  true,
+       'C':  true,
+       'D':  true,
+       'E':  true,
+       'F':  true,
+       'G':  true,
+       'H':  true,
+       'I':  true,
+       'J':  true,
+       'K':  true,
+       'L':  true,
+       'M':  true,
+       'N':  true,
+       'O':  true,
+       'P':  true,
+       'Q':  true,
+       'R':  true,
+       'S':  true,
+       'T':  true,
+       'U':  true,
+       'W':  true,
+       'V':  true,
+       'X':  true,
+       'Y':  true,
+       'Z':  true,
+       '^':  true,
+       '_':  true,
+       '`':  true,
+       'a':  true,
+       'b':  true,
+       'c':  true,
+       'd':  true,
+       'e':  true,
+       'f':  true,
+       'g':  true,
+       'h':  true,
+       'i':  true,
+       'j':  true,
+       'k':  true,
+       'l':  true,
+       'm':  true,
+       'n':  true,
+       'o':  true,
+       'p':  true,
+       'q':  true,
+       'r':  true,
+       's':  true,
+       't':  true,
+       'u':  true,
+       'v':  true,
+       'w':  true,
+       'x':  true,
+       'y':  true,
+       'z':  true,
+       '|':  true,
+       '~':  true,
+}
+
+// pipe is a goroutine-safe io.Reader/io.Writer pair.  It's like
+// io.Pipe except there are no PipeReader/PipeWriter halves, and the
+// underlying buffer is an interface. (io.Pipe is always unbuffered)
+type http2pipe struct {
+       mu       sync.Mutex
+       c        sync.Cond // c.L lazily initialized to &p.mu
+       b        http2pipeBuffer
+       err      error         // read error once empty. non-nil means closed.
+       breakErr error         // immediate read error (caller doesn't see rest of b)
+       donec    chan struct{} // closed on error
+       readFn   func()        // optional code to run in Read before error
+}
+
+type http2pipeBuffer interface {
+       Len() int
+       io.Writer
+       io.Reader
+}
+
+// Read waits until data is available and copies bytes
+// from the buffer into p.
+func (p *http2pipe) Read(d []byte) (n int, err error) {
+       p.mu.Lock()
+       defer p.mu.Unlock()
+       if p.c.L == nil {
+               p.c.L = &p.mu
+       }
+       for {
+               if p.breakErr != nil {
+                       return 0, p.breakErr
+               }
+               if p.b.Len() > 0 {
+                       return p.b.Read(d)
+               }
+               if p.err != nil {
+                       if p.readFn != nil {
+                               p.readFn()
+                               p.readFn = nil
+                       }
+                       return 0, p.err
+               }
+               p.c.Wait()
+       }
+}
+
+var http2errClosedPipeWrite = errors.New("write on closed buffer")
+
+// Write copies bytes from p into the buffer and wakes a reader.
+// It is an error to write more data than the buffer can hold.
+func (p *http2pipe) Write(d []byte) (n int, err error) {
+       p.mu.Lock()
+       defer p.mu.Unlock()
+       if p.c.L == nil {
+               p.c.L = &p.mu
+       }
+       defer p.c.Signal()
+       if p.err != nil {
+               return 0, http2errClosedPipeWrite
+       }
+       return p.b.Write(d)
+}
+
+// CloseWithError causes the next Read (waking up a current blocked
+// Read if needed) to return the provided err after all data has been
+// read.
+//
+// The error must be non-nil.
+func (p *http2pipe) CloseWithError(err error) { p.closeWithError(&p.err, err, nil) }
+
+// BreakWithError causes the next Read (waking up a current blocked
+// Read if needed) to return the provided err immediately, without
+// waiting for unread data.
+func (p *http2pipe) BreakWithError(err error) { p.closeWithError(&p.breakErr, err, nil) }
+
+// closeWithErrorAndCode is like CloseWithError but also sets some code to run
+// in the caller's goroutine before returning the error.
+func (p *http2pipe) closeWithErrorAndCode(err error, fn func()) { p.closeWithError(&p.err, err, fn) }
+
+func (p *http2pipe) closeWithError(dst *error, err error, fn func()) {
+       if err == nil {
+               panic("err must be non-nil")
+       }
+       p.mu.Lock()
+       defer p.mu.Unlock()
+       if p.c.L == nil {
+               p.c.L = &p.mu
+       }
+       defer p.c.Signal()
+       if *dst != nil {
+
+               return
+       }
+       p.readFn = fn
+       *dst = err
+       p.closeDoneLocked()
+}
+
+// requires p.mu be held.
+func (p *http2pipe) closeDoneLocked() {
+       if p.donec == nil {
+               return
+       }
+
+       select {
+       case <-p.donec:
+       default:
+               close(p.donec)
+       }
+}
+
+// Err returns the error (if any) first set by BreakWithError or CloseWithError.
+func (p *http2pipe) Err() error {
+       p.mu.Lock()
+       defer p.mu.Unlock()
+       if p.breakErr != nil {
+               return p.breakErr
+       }
+       return p.err
+}
+
+// Done returns a channel which is closed if and when this pipe is closed
+// with CloseWithError.
+func (p *http2pipe) Done() <-chan struct{} {
+       p.mu.Lock()
+       defer p.mu.Unlock()
+       if p.donec == nil {
+               p.donec = make(chan struct{})
+               if p.err != nil || p.breakErr != nil {
+
+                       p.closeDoneLocked()
+               }
+       }
+       return p.donec
+}
+
+const (
+       http2prefaceTimeout        = 10 * time.Second
+       http2firstSettingsTimeout  = 2 * time.Second // should be in-flight with preface anyway
+       http2handlerChunkWriteSize = 4 << 10
+       http2defaultMaxStreams     = 250 // TODO: make this 100 as the GFE seems to?
+)
+
+var (
+       http2errClientDisconnected = errors.New("client disconnected")
+       http2errClosedBody         = errors.New("body closed by handler")
+       http2errHandlerComplete    = errors.New("http2: request body closed due to handler exiting")
+       http2errStreamClosed       = errors.New("http2: stream closed")
+)
+
+var http2responseWriterStatePool = sync.Pool{
+       New: func() interface{} {
+               rws := &http2responseWriterState{}
+               rws.bw = bufio.NewWriterSize(http2chunkWriter{rws}, http2handlerChunkWriteSize)
+               return rws
+       },
+}
+
+// Test hooks.
+var (
+       http2testHookOnConn        func()
+       http2testHookGetServerConn func(*http2serverConn)
+       http2testHookOnPanicMu     *sync.Mutex // nil except in tests
+       http2testHookOnPanic       func(sc *http2serverConn, panicVal interface{}) (rePanic bool)
+)
+
+// Server is an HTTP/2 server.
+type http2Server struct {
+       // MaxHandlers limits the number of http.Handler ServeHTTP goroutines
+       // which may run at a time over all connections.
+       // Negative or zero no limit.
+       // TODO: implement
+       MaxHandlers int
+
+       // MaxConcurrentStreams optionally specifies the number of
+       // concurrent streams that each client may have open at a
+       // time. This is unrelated to the number of http.Handler goroutines
+       // which may be active globally, which is MaxHandlers.
+       // If zero, MaxConcurrentStreams defaults to at least 100, per
+       // the HTTP/2 spec's recommendations.
+       MaxConcurrentStreams uint32
+
+       // MaxReadFrameSize optionally specifies the largest frame
+       // this server is willing to read. A valid value is between
+       // 16k and 16M, inclusive. If zero or otherwise invalid, a
+       // default value is used.
+       MaxReadFrameSize uint32
+
+       // PermitProhibitedCipherSuites, if true, permits the use of
+       // cipher suites prohibited by the HTTP/2 spec.
+       PermitProhibitedCipherSuites bool
+}
+
+func (s *http2Server) maxReadFrameSize() uint32 {
+       if v := s.MaxReadFrameSize; v >= http2minMaxFrameSize && v <= http2maxFrameSize {
+               return v
+       }
+       return http2defaultMaxReadFrameSize
+}
+
+func (s *http2Server) maxConcurrentStreams() uint32 {
+       if v := s.MaxConcurrentStreams; v > 0 {
+               return v
+       }
+       return http2defaultMaxStreams
+}
+
+// ConfigureServer adds HTTP/2 support to a net/http Server.
+//
+// The configuration conf may be nil.
+//
+// ConfigureServer must be called before s begins serving.
+func http2ConfigureServer(s *Server, conf *http2Server) error {
+       if conf == nil {
+               conf = new(http2Server)
+       }
+
+       if s.TLSConfig == nil {
+               s.TLSConfig = new(tls.Config)
+       } else if s.TLSConfig.CipherSuites != nil {
+               // If they already provided a CipherSuite list, return
+               // an error if it has a bad order or is missing
+               // ECDHE_RSA_WITH_AES_128_GCM_SHA256.
+               const requiredCipher = tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+               haveRequired := false
+               sawBad := false
+               for i, cs := range s.TLSConfig.CipherSuites {
+                       if cs == requiredCipher {
+                               haveRequired = true
+                       }
+                       if http2isBadCipher(cs) {
+                               sawBad = true
+                       } else if sawBad {
+                               return fmt.Errorf("http2: TLSConfig.CipherSuites index %d contains an HTTP/2-approved cipher suite (%#04x), but it comes after unapproved cipher suites. With this configuration, clients that don't support previous, approved cipher suites may be given an unapproved one and reject the connection.", i, cs)
+                       }
+               }
+               if !haveRequired {
+                       return fmt.Errorf("http2: TLSConfig.CipherSuites is missing HTTP/2-required TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")
+               }
+       }
+
+       s.TLSConfig.PreferServerCipherSuites = true
+
+       haveNPN := false
+       for _, p := range s.TLSConfig.NextProtos {
+               if p == http2NextProtoTLS {
+                       haveNPN = true
+                       break
+               }
+       }
+       if !haveNPN {
+               s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, http2NextProtoTLS)
+       }
+
+       s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "h2-14")
+
+       if s.TLSNextProto == nil {
+               s.TLSNextProto = map[string]func(*Server, *tls.Conn, Handler){}
+       }
+       protoHandler := func(hs *Server, c *tls.Conn, h Handler) {
+               if http2testHookOnConn != nil {
+                       http2testHookOnConn()
+               }
+               conf.handleConn(hs, c, h)
+       }
+       s.TLSNextProto[http2NextProtoTLS] = protoHandler
+       s.TLSNextProto["h2-14"] = protoHandler
+       return nil
+}
+
+func (srv *http2Server) handleConn(hs *Server, c net.Conn, h Handler) {
+       sc := &http2serverConn{
+               srv:              srv,
+               hs:               hs,
+               conn:             c,
+               remoteAddrStr:    c.RemoteAddr().String(),
+               bw:               http2newBufferedWriter(c),
+               handler:          h,
+               streams:          make(map[uint32]*http2stream),
+               readFrameCh:      make(chan http2readFrameResult),
+               wantWriteFrameCh: make(chan http2frameWriteMsg, 8),
+               wroteFrameCh:     make(chan http2frameWriteResult, 1),
+               bodyReadCh:       make(chan http2bodyReadMsg),
+               doneServing:      make(chan struct{}),
+               advMaxStreams:    srv.maxConcurrentStreams(),
+               writeSched: http2writeScheduler{
+                       maxFrameSize: http2initialMaxFrameSize,
+               },
+               initialWindowSize: http2initialWindowSize,
+               headerTableSize:   http2initialHeaderTableSize,
+               serveG:            http2newGoroutineLock(),
+               pushEnabled:       true,
+       }
+       sc.flow.add(http2initialWindowSize)
+       sc.inflow.add(http2initialWindowSize)
+       sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
+       sc.hpackDecoder = hpack.NewDecoder(http2initialHeaderTableSize, nil)
+       sc.hpackDecoder.SetMaxStringLength(sc.maxHeaderStringLen())
+
+       fr := http2NewFramer(sc.bw, c)
+       fr.SetMaxReadFrameSize(srv.maxReadFrameSize())
+       sc.framer = fr
+
+       if tc, ok := c.(*tls.Conn); ok {
+               sc.tlsState = new(tls.ConnectionState)
+               *sc.tlsState = tc.ConnectionState()
+
+               if sc.tlsState.Version < tls.VersionTLS12 {
+                       sc.rejectConn(http2ErrCodeInadequateSecurity, "TLS version too low")
+                       return
+               }
+
+               if sc.tlsState.ServerName == "" {
+
+               }
+
+               if !srv.PermitProhibitedCipherSuites && http2isBadCipher(sc.tlsState.CipherSuite) {
+
+                       sc.rejectConn(http2ErrCodeInadequateSecurity, fmt.Sprintf("Prohibited TLS 1.2 Cipher Suite: %x", sc.tlsState.CipherSuite))
+                       return
+               }
+       }
+
+       if hook := http2testHookGetServerConn; hook != nil {
+               hook(sc)
+       }
+       sc.serve()
+}
+
+// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
+func http2isBadCipher(cipher uint16) bool {
+       switch cipher {
+       case tls.TLS_RSA_WITH_RC4_128_SHA,
+               tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+               tls.TLS_RSA_WITH_AES_128_CBC_SHA,
+               tls.TLS_RSA_WITH_AES_256_CBC_SHA,
+               tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+               tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+               tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+               tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+               tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+               tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+               tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+
+               return true
+       default:
+               return false
+       }
+}
+
+func (sc *http2serverConn) rejectConn(err http2ErrCode, debug string) {
+       sc.vlogf("http2: server rejecting conn: %v, %s", err, debug)
+
+       sc.framer.WriteGoAway(0, err, []byte(debug))
+       sc.bw.Flush()
+       sc.conn.Close()
+}
+
+type http2serverConn struct {
+       // Immutable:
+       srv              *http2Server
+       hs               *Server
+       conn             net.Conn
+       bw               *http2bufferedWriter // writing to conn
+       handler          Handler
+       framer           *http2Framer
+       hpackDecoder     *hpack.Decoder
+       doneServing      chan struct{}              // closed when serverConn.serve ends
+       readFrameCh      chan http2readFrameResult  // written by serverConn.readFrames
+       wantWriteFrameCh chan http2frameWriteMsg    // from handlers -> serve
+       wroteFrameCh     chan http2frameWriteResult // from writeFrameAsync -> serve, tickles more frame writes
+       bodyReadCh       chan http2bodyReadMsg      // from handlers -> serve
+       testHookCh       chan func(int)             // code to run on the serve loop
+       flow             http2flow                  // conn-wide (not stream-specific) outbound flow control
+       inflow           http2flow                  // conn-wide inbound flow control
+       tlsState         *tls.ConnectionState       // shared by all handlers, like net/http
+       remoteAddrStr    string
+
+       // Everything following is owned by the serve loop; use serveG.check():
+       serveG                http2goroutineLock // used to verify funcs are on serve()
+       pushEnabled           bool
+       sawFirstSettings      bool // got the initial SETTINGS frame after the preface
+       needToSendSettingsAck bool
+       unackedSettings       int    // how many SETTINGS have we sent without ACKs?
+       clientMaxStreams      uint32 // SETTINGS_MAX_CONCURRENT_STREAMS from client (our PUSH_PROMISE limit)
+       advMaxStreams         uint32 // our SETTINGS_MAX_CONCURRENT_STREAMS advertised the client
+       curOpenStreams        uint32 // client's number of open streams
+       maxStreamID           uint32 // max ever seen
+       streams               map[uint32]*http2stream
+       initialWindowSize     int32
+       headerTableSize       uint32
+       peerMaxHeaderListSize uint32            // zero means unknown (default)
+       canonHeader           map[string]string // http2-lower-case -> Go-Canonical-Case
+       req                   http2requestParam // non-zero while reading request headers
+       writingFrame          bool              // started write goroutine but haven't heard back on wroteFrameCh
+       needsFrameFlush       bool              // last frame write wasn't a flush
+       writeSched            http2writeScheduler
+       inGoAway              bool // we've started to or sent GOAWAY
+       needToSendGoAway      bool // we need to schedule a GOAWAY frame write
+       goAwayCode            http2ErrCode
+       shutdownTimerCh       <-chan time.Time // nil until used
+       shutdownTimer         *time.Timer      // nil until used
+
+       // Owned by the writeFrameAsync goroutine:
+       headerWriteBuf bytes.Buffer
+       hpackEncoder   *hpack.Encoder
+}
+
+func (sc *http2serverConn) maxHeaderStringLen() int {
+       v := sc.maxHeaderListSize()
+       if uint32(int(v)) == v {
+               return int(v)
+       }
+
+       return 0
+}
+
+func (sc *http2serverConn) maxHeaderListSize() uint32 {
+       n := sc.hs.MaxHeaderBytes
+       if n <= 0 {
+               n = DefaultMaxHeaderBytes
+       }
+       // http2's count is in a slightly different unit and includes 32 bytes per pair.
+       // So, take the net/http.Server value and pad it up a bit, assuming 10 headers.
+       const perFieldOverhead = 32 // per http2 spec
+       const typicalHeaders = 10   // conservative
+       return uint32(n + typicalHeaders*perFieldOverhead)
+}
+
+// requestParam is the state of the next request, initialized over
+// potentially several frames HEADERS + zero or more CONTINUATION
+// frames.
+type http2requestParam struct {
+       // stream is non-nil if we're reading (HEADER or CONTINUATION)
+       // frames for a request (but not DATA).
+       stream            *http2stream
+       header            Header
+       method, path      string
+       scheme, authority string
+       sawRegularHeader  bool  // saw a non-pseudo header already
+       invalidHeader     bool  // an invalid header was seen
+       headerListSize    int64 // actually uint32, but easier math this way
+}
+
+// stream represents a stream. This is the minimal metadata needed by
+// the serve goroutine. Most of the actual stream state is owned by
+// the http.Handler's goroutine in the responseWriter. Because the
+// responseWriter's responseWriterState is recycled at the end of a
+// handler, this struct intentionally has no pointer to the
+// *responseWriter{,State} itself, as the Handler ending nils out the
+// responseWriter's state field.
+type http2stream struct {
+       // immutable:
+       sc   *http2serverConn
+       id   uint32
+       body *http2pipe       // non-nil if expecting DATA frames
+       cw   http2closeWaiter // closed wait stream transitions to closed state
+
+       // owned by serverConn's serve loop:
+       bodyBytes        int64        // body bytes seen so far
+       declBodyBytes    int64        // or -1 if undeclared
+       flow             http2flow    // limits writing from Handler to client
+       inflow           http2flow    // what the client is allowed to POST/etc to us
+       parent           *http2stream // or nil
+       numTrailerValues int64
+       weight           uint8
+       state            http2streamState
+       sentReset        bool // only true once detached from streams map
+       gotReset         bool // only true once detacted from streams map
+       gotTrailerHeader bool // HEADER frame for trailers was seen
+
+       trailer    Header // accumulated trailers
+       reqTrailer Header // handler's Request.Trailer
+}
+
+func (sc *http2serverConn) Framer() *http2Framer { return sc.framer }
+
+func (sc *http2serverConn) CloseConn() error { return sc.conn.Close() }
+
+func (sc *http2serverConn) Flush() error { return sc.bw.Flush() }
+
+func (sc *http2serverConn) HeaderEncoder() (*hpack.Encoder, *bytes.Buffer) {
+       return sc.hpackEncoder, &sc.headerWriteBuf
+}
+
+func (sc *http2serverConn) state(streamID uint32) (http2streamState, *http2stream) {
+       sc.serveG.check()
+
+       if st, ok := sc.streams[streamID]; ok {
+               return st.state, st
+       }
+
+       if streamID <= sc.maxStreamID {
+               return http2stateClosed, nil
+       }
+       return http2stateIdle, nil
+}
+
+// setConnState calls the net/http ConnState hook for this connection, if configured.
+// Note that the net/http package does StateNew and StateClosed for us.
+// There is currently no plan for StateHijacked or hijacking HTTP/2 connections.
+func (sc *http2serverConn) setConnState(state ConnState) {
+       if sc.hs.ConnState != nil {
+               sc.hs.ConnState(sc.conn, state)
+       }
+}
+
+func (sc *http2serverConn) vlogf(format string, args ...interface{}) {
+       if http2VerboseLogs {
+               sc.logf(format, args...)
+       }
+}
+
+func (sc *http2serverConn) logf(format string, args ...interface{}) {
+       if lg := sc.hs.ErrorLog; lg != nil {
+               lg.Printf(format, args...)
+       } else {
+               log.Printf(format, args...)
+       }
+}
+
+var http2uintptrType = reflect.TypeOf(uintptr(0))
+
+// errno returns v's underlying uintptr, else 0.
+//
+// TODO: remove this helper function once http2 can use build
+// tags. See comment in isClosedConnError.
+func http2errno(v error) uintptr {
+       if rv := reflect.ValueOf(v); rv.Kind() == reflect.Uintptr {
+               return uintptr(rv.Uint())
+       }
+       return 0
+}
+
+// isClosedConnError reports whether err is an error from use of a closed
+// network connection.
+func http2isClosedConnError(err error) bool {
+       if err == nil {
+               return false
+       }
+
+       str := err.Error()
+       if strings.Contains(str, "use of closed network connection") {
+               return true
+       }
+
+       if runtime.GOOS == "windows" {
+               if oe, ok := err.(*net.OpError); ok && oe.Op == "read" {
+                       if se, ok := oe.Err.(*os.SyscallError); ok && se.Syscall == "wsarecv" {
+                               const WSAECONNABORTED = 10053
+                               const WSAECONNRESET = 10054
+                               if n := http2errno(se.Err); n == WSAECONNRESET || n == WSAECONNABORTED {
+                                       return true
+                               }
+                       }
+               }
+       }
+       return false
+}
+
+func (sc *http2serverConn) condlogf(err error, format string, args ...interface{}) {
+       if err == nil {
+               return
+       }
+       if err == io.EOF || err == io.ErrUnexpectedEOF || http2isClosedConnError(err) {
+
+               sc.vlogf(format, args...)
+       } else {
+               sc.logf(format, args...)
+       }
+}
+
+func (sc *http2serverConn) onNewHeaderField(f hpack.HeaderField) {
+       sc.serveG.check()
+       if http2VerboseLogs {
+               sc.vlogf("http2: server decoded %v", f)
+       }
+       switch {
+       case !http2validHeaderFieldValue(f.Value):
+               sc.req.invalidHeader = true
+       case strings.HasPrefix(f.Name, ":"):
+               if sc.req.sawRegularHeader {
+                       sc.logf("pseudo-header after regular header")
+                       sc.req.invalidHeader = true
+                       return
+               }
+               var dst *string
+               switch f.Name {
+               case ":method":
+                       dst = &sc.req.method
+               case ":path":
+                       dst = &sc.req.path
+               case ":scheme":
+                       dst = &sc.req.scheme
+               case ":authority":
+                       dst = &sc.req.authority
+               default:
+
+                       sc.logf("invalid pseudo-header %q", f.Name)
+                       sc.req.invalidHeader = true
+                       return
+               }
+               if *dst != "" {
+                       sc.logf("duplicate pseudo-header %q sent", f.Name)
+                       sc.req.invalidHeader = true
+                       return
+               }
+               *dst = f.Value
+       case !http2validHeaderFieldName(f.Name):
+               sc.req.invalidHeader = true
+       default:
+               sc.req.sawRegularHeader = true
+               sc.req.header.Add(sc.canonicalHeader(f.Name), f.Value)
+               const headerFieldOverhead = 32 // per spec
+               sc.req.headerListSize += int64(len(f.Name)) + int64(len(f.Value)) + headerFieldOverhead
+               if sc.req.headerListSize > int64(sc.maxHeaderListSize()) {
+                       sc.hpackDecoder.SetEmitEnabled(false)
+               }
+       }
+}
+
+func (st *http2stream) onNewTrailerField(f hpack.HeaderField) {
+       sc := st.sc
+       sc.serveG.check()
+       if http2VerboseLogs {
+               sc.vlogf("http2: server decoded trailer %v", f)
+       }
+       switch {
+       case strings.HasPrefix(f.Name, ":"):
+               sc.req.invalidHeader = true
+               return
+       case !http2validHeaderFieldName(f.Name) || !http2validHeaderFieldValue(f.Value):
+               sc.req.invalidHeader = true
+               return
+       default:
+               key := sc.canonicalHeader(f.Name)
+               if st.trailer != nil {
+                       vv := append(st.trailer[key], f.Value)
+                       st.trailer[key] = vv
+
+                       // arbitrary; TODO: read spec about header list size limits wrt trailers
+                       const tooBig = 1000
+                       if len(vv) >= tooBig {
+                               sc.hpackDecoder.SetEmitEnabled(false)
+                       }
+               }
+       }
+}
+
+func (sc *http2serverConn) canonicalHeader(v string) string {
+       sc.serveG.check()
+       cv, ok := http2commonCanonHeader[v]
+       if ok {
+               return cv
+       }
+       cv, ok = sc.canonHeader[v]
+       if ok {
+               return cv
+       }
+       if sc.canonHeader == nil {
+               sc.canonHeader = make(map[string]string)
+       }
+       cv = CanonicalHeaderKey(v)
+       sc.canonHeader[v] = cv
+       return cv
+}
+
+type http2readFrameResult struct {
+       f   http2Frame // valid until readMore is called
+       err error
+
+       // readMore should be called once the consumer no longer needs or
+       // retains f. After readMore, f is invalid and more frames can be
+       // read.
+       readMore func()
+}
+
+// readFrames is the loop that reads incoming frames.
+// It takes care to only read one frame at a time, blocking until the
+// consumer is done with the frame.
+// It's run on its own goroutine.
+func (sc *http2serverConn) readFrames() {
+       gate := make(http2gate)
+       for {
+               f, err := sc.framer.ReadFrame()
+               select {
+               case sc.readFrameCh <- http2readFrameResult{f, err, gate.Done}:
+               case <-sc.doneServing:
+                       return
+               }
+               select {
+               case <-gate:
+               case <-sc.doneServing:
+                       return
+               }
+               if http2terminalReadFrameError(err) {
+                       return
+               }
+       }
+}
+
+// frameWriteResult is the message passed from writeFrameAsync to the serve goroutine.
+type http2frameWriteResult struct {
+       wm  http2frameWriteMsg // what was written (or attempted)
+       err error              // result of the writeFrame call
+}
+
+// writeFrameAsync runs in its own goroutine and writes a single frame
+// and then reports when it's done.
+// At most one goroutine can be running writeFrameAsync at a time per
+// serverConn.
+func (sc *http2serverConn) writeFrameAsync(wm http2frameWriteMsg) {
+       err := wm.write.writeFrame(sc)
+       sc.wroteFrameCh <- http2frameWriteResult{wm, err}
+}
+
+func (sc *http2serverConn) closeAllStreamsOnConnClose() {
+       sc.serveG.check()
+       for _, st := range sc.streams {
+               sc.closeStream(st, http2errClientDisconnected)
+       }
+}
+
+func (sc *http2serverConn) stopShutdownTimer() {
+       sc.serveG.check()
+       if t := sc.shutdownTimer; t != nil {
+               t.Stop()
+       }
+}
+
+func (sc *http2serverConn) notePanic() {
+
+       if http2testHookOnPanicMu != nil {
+               http2testHookOnPanicMu.Lock()
+               defer http2testHookOnPanicMu.Unlock()
+       }
+       if http2testHookOnPanic != nil {
+               if e := recover(); e != nil {
+                       if http2testHookOnPanic(sc, e) {
+                               panic(e)
+                       }
+               }
+       }
+}
+
+func (sc *http2serverConn) serve() {
+       sc.serveG.check()
+       defer sc.notePanic()
+       defer sc.conn.Close()
+       defer sc.closeAllStreamsOnConnClose()
+       defer sc.stopShutdownTimer()
+       defer close(sc.doneServing)
+
+       if http2VerboseLogs {
+               sc.vlogf("http2: server connection from %v on %p", sc.conn.RemoteAddr(), sc.hs)
+       }
+
+       sc.writeFrame(http2frameWriteMsg{
+               write: http2writeSettings{
+                       {http2SettingMaxFrameSize, sc.srv.maxReadFrameSize()},
+                       {http2SettingMaxConcurrentStreams, sc.advMaxStreams},
+                       {http2SettingMaxHeaderListSize, sc.maxHeaderListSize()},
+               },
+       })
+       sc.unackedSettings++
+
+       if err := sc.readPreface(); err != nil {
+               sc.condlogf(err, "http2: server: error reading preface from client %v: %v", sc.conn.RemoteAddr(), err)
+               return
+       }
+
+       sc.setConnState(StateActive)
+       sc.setConnState(StateIdle)
+
+       go sc.readFrames()
+
+       settingsTimer := time.NewTimer(http2firstSettingsTimeout)
+       loopNum := 0
+       for {
+               loopNum++
+               select {
+               case wm := <-sc.wantWriteFrameCh:
+                       sc.writeFrame(wm)
+               case res := <-sc.wroteFrameCh:
+                       sc.wroteFrame(res)
+               case res := <-sc.readFrameCh:
+                       if !sc.processFrameFromReader(res) {
+                               return
+                       }
+                       res.readMore()
+                       if settingsTimer.C != nil {
+                               settingsTimer.Stop()
+                               settingsTimer.C = nil
+                       }
+               case m := <-sc.bodyReadCh:
+                       sc.noteBodyRead(m.st, m.n)
+               case <-settingsTimer.C:
+                       sc.logf("timeout waiting for SETTINGS frames from %v", sc.conn.RemoteAddr())
+                       return
+               case <-sc.shutdownTimerCh:
+                       sc.vlogf("GOAWAY close timer fired; closing conn from %v", sc.conn.RemoteAddr())
+                       return
+               case fn := <-sc.testHookCh:
+                       fn(loopNum)
+               }
+       }
+}
+
+// readPreface reads the ClientPreface greeting from the peer
+// or returns an error on timeout or an invalid greeting.
+func (sc *http2serverConn) readPreface() error {
+       errc := make(chan error, 1)
+       go func() {
+
+               buf := make([]byte, len(http2ClientPreface))
+               if _, err := io.ReadFull(sc.conn, buf); err != nil {
+                       errc <- err
+               } else if !bytes.Equal(buf, http2clientPreface) {
+                       errc <- fmt.Errorf("bogus greeting %q", buf)
+               } else {
+                       errc <- nil
+               }
+       }()
+       timer := time.NewTimer(http2prefaceTimeout)
+       defer timer.Stop()
+       select {
+       case <-timer.C:
+               return errors.New("timeout waiting for client preface")
+       case err := <-errc:
+               if err == nil {
+                       if http2VerboseLogs {
+                               sc.vlogf("http2: server: client %v said hello", sc.conn.RemoteAddr())
+                       }
+               }
+               return err
+       }
+}
+
+var http2errChanPool = sync.Pool{
+       New: func() interface{} { return make(chan error, 1) },
+}
+
+var http2writeDataPool = sync.Pool{
+       New: func() interface{} { return new(http2writeData) },
+}
+
+// writeDataFromHandler writes DATA response frames from a handler on
+// the given stream.
+func (sc *http2serverConn) writeDataFromHandler(stream *http2stream, data []byte, endStream bool) error {
+       ch := http2errChanPool.Get().(chan error)
+       writeArg := http2writeDataPool.Get().(*http2writeData)
+       *writeArg = http2writeData{stream.id, data, endStream}
+       err := sc.writeFrameFromHandler(http2frameWriteMsg{
+               write:  writeArg,
+               stream: stream,
+               done:   ch,
+       })
+       if err != nil {
+               return err
+       }
+       var frameWriteDone bool // the frame write is done (successfully or not)
+       select {
+       case err = <-ch:
+               frameWriteDone = true
+       case <-sc.doneServing:
+               return http2errClientDisconnected
+       case <-stream.cw:
+
+               select {
+               case err = <-ch:
+                       frameWriteDone = true
+               default:
+                       return http2errStreamClosed
+               }
+       }
+       http2errChanPool.Put(ch)
+       if frameWriteDone {
+               http2writeDataPool.Put(writeArg)
+       }
+       return err
+}
+
+// writeFrameFromHandler sends wm to sc.wantWriteFrameCh, but aborts
+// if the connection has gone away.
+//
+// This must not be run from the serve goroutine itself, else it might
+// deadlock writing to sc.wantWriteFrameCh (which is only mildly
+// buffered and is read by serve itself). If you're on the serve
+// goroutine, call writeFrame instead.
+func (sc *http2serverConn) writeFrameFromHandler(wm http2frameWriteMsg) error {
+       sc.serveG.checkNotOn()
+       select {
+       case sc.wantWriteFrameCh <- wm:
+               return nil
+       case <-sc.doneServing:
+
+               return http2errClientDisconnected
+       }
+}
+
+// writeFrame schedules a frame to write and sends it if there's nothing
+// already being written.
+//
+// There is no pushback here (the serve goroutine never blocks). It's
+// the http.Handlers that block, waiting for their previous frames to
+// make it onto the wire
+//
+// If you're not on the serve goroutine, use writeFrameFromHandler instead.
+func (sc *http2serverConn) writeFrame(wm http2frameWriteMsg) {
+       sc.serveG.check()
+       sc.writeSched.add(wm)
+       sc.scheduleFrameWrite()
+}
+
+// startFrameWrite starts a goroutine to write wm (in a separate
+// goroutine since that might block on the network), and updates the
+// serve goroutine's state about the world, updated from info in wm.
+func (sc *http2serverConn) startFrameWrite(wm http2frameWriteMsg) {
+       sc.serveG.check()
+       if sc.writingFrame {
+               panic("internal error: can only be writing one frame at a time")
+       }
+
+       st := wm.stream
+       if st != nil {
+               switch st.state {
+               case http2stateHalfClosedLocal:
+                       panic("internal error: attempt to send frame on half-closed-local stream")
+               case http2stateClosed:
+                       if st.sentReset || st.gotReset {
+
+                               sc.scheduleFrameWrite()
+                               return
+                       }
+                       panic(fmt.Sprintf("internal error: attempt to send a write %v on a closed stream", wm))
+               }
+       }
+
+       sc.writingFrame = true
+       sc.needsFrameFlush = true
+       go sc.writeFrameAsync(wm)
+}
+
+// errHandlerPanicked is the error given to any callers blocked in a read from
+// Request.Body when the main goroutine panics. Since most handlers read in the
+// the main ServeHTTP goroutine, this will show up rarely.
+var http2errHandlerPanicked = errors.New("http2: handler panicked")
+
+// wroteFrame is called on the serve goroutine with the result of
+// whatever happened on writeFrameAsync.
+func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) {
+       sc.serveG.check()
+       if !sc.writingFrame {
+               panic("internal error: expected to be already writing a frame")
+       }
+       sc.writingFrame = false
+
+       wm := res.wm
+       st := wm.stream
+
+       closeStream := http2endsStream(wm.write)
+
+       if _, ok := wm.write.(http2handlerPanicRST); ok {
+               sc.closeStream(st, http2errHandlerPanicked)
+       }
+
+       if ch := wm.done; ch != nil {
+               select {
+               case ch <- res.err:
+               default:
+                       panic(fmt.Sprintf("unbuffered done channel passed in for type %T", wm.write))
+               }
+       }
+       wm.write = nil
+
+       if closeStream {
+               if st == nil {
+                       panic("internal error: expecting non-nil stream")
+               }
+               switch st.state {
+               case http2stateOpen:
+
+                       st.state = http2stateHalfClosedLocal
+                       errCancel := http2StreamError{st.id, http2ErrCodeCancel}
+                       sc.resetStream(errCancel)
+               case http2stateHalfClosedRemote:
+                       sc.closeStream(st, http2errHandlerComplete)
+               }
+       }
+
+       sc.scheduleFrameWrite()
+}
+
+// scheduleFrameWrite tickles the frame writing scheduler.
+//
+// If a frame is already being written, nothing happens. This will be called again
+// when the frame is done being written.
+//
+// If a frame isn't being written we need to send one, the best frame
+// to send is selected, preferring first things that aren't
+// stream-specific (e.g. ACKing settings), and then finding the
+// highest priority stream.
+//
+// If a frame isn't being written and there's nothing else to send, we
+// flush the write buffer.
+func (sc *http2serverConn) scheduleFrameWrite() {
+       sc.serveG.check()
+       if sc.writingFrame {
+               return
+       }
+       if sc.needToSendGoAway {
+               sc.needToSendGoAway = false
+               sc.startFrameWrite(http2frameWriteMsg{
+                       write: &http2writeGoAway{
+                               maxStreamID: sc.maxStreamID,
+                               code:        sc.goAwayCode,
+                       },
+               })
+               return
+       }
+       if sc.needToSendSettingsAck {
+               sc.needToSendSettingsAck = false
+               sc.startFrameWrite(http2frameWriteMsg{write: http2writeSettingsAck{}})
+               return
+       }
+       if !sc.inGoAway {
+               if wm, ok := sc.writeSched.take(); ok {
+                       sc.startFrameWrite(wm)
+                       return
+               }
+       }
+       if sc.needsFrameFlush {
+               sc.startFrameWrite(http2frameWriteMsg{write: http2flushFrameWriter{}})
+               sc.needsFrameFlush = false
+               return
+       }
+}
+
+func (sc *http2serverConn) goAway(code http2ErrCode) {
+       sc.serveG.check()
+       if sc.inGoAway {
+               return
+       }
+       if code != http2ErrCodeNo {
+               sc.shutDownIn(250 * time.Millisecond)
+       } else {
+
+               sc.shutDownIn(1 * time.Second)
+       }
+       sc.inGoAway = true
+       sc.needToSendGoAway = true
+       sc.goAwayCode = code
+       sc.scheduleFrameWrite()
+}
+
+func (sc *http2serverConn) shutDownIn(d time.Duration) {
+       sc.serveG.check()
+       sc.shutdownTimer = time.NewTimer(d)
+       sc.shutdownTimerCh = sc.shutdownTimer.C
+}
+
+func (sc *http2serverConn) resetStream(se http2StreamError) {
+       sc.serveG.check()
+       sc.writeFrame(http2frameWriteMsg{write: se})
+       if st, ok := sc.streams[se.StreamID]; ok {
+               st.sentReset = true
+               sc.closeStream(st, se)
+       }
+}
+
+// processFrameFromReader processes the serve loop's read from readFrameCh from the
+// frame-reading goroutine.
+// processFrameFromReader returns whether the connection should be kept open.
+func (sc *http2serverConn) processFrameFromReader(res http2readFrameResult) bool {
+       sc.serveG.check()
+       err := res.err
+       if err != nil {
+               if err == http2ErrFrameTooLarge {
+                       sc.goAway(http2ErrCodeFrameSize)
+                       return true
+               }
+               clientGone := err == io.EOF || err == io.ErrUnexpectedEOF || http2isClosedConnError(err)
+               if clientGone {
+
+                       return false
+               }
+       } else {
+               f := res.f
+               if http2VerboseLogs {
+                       sc.vlogf("http2: server read frame %v", http2summarizeFrame(f))
+               }
+               err = sc.processFrame(f)
+               if err == nil {
+                       return true
+               }
+       }
+
+       switch ev := err.(type) {
+       case http2StreamError:
+               sc.resetStream(ev)
+               return true
+       case http2goAwayFlowError:
+               sc.goAway(http2ErrCodeFlowControl)
+               return true
+       case http2ConnectionError:
+               sc.logf("http2: server connection error from %v: %v", sc.conn.RemoteAddr(), ev)
+               sc.goAway(http2ErrCode(ev))
+               return true
+       default:
+               if res.err != nil {
+                       sc.vlogf("http2: server closing client connection; error reading frame from client %s: %v", sc.conn.RemoteAddr(), err)
+               } else {
+                       sc.logf("http2: server closing client connection: %v", err)
+               }
+               return false
+       }
+}
+
+func (sc *http2serverConn) processFrame(f http2Frame) error {
+       sc.serveG.check()
+
+       if !sc.sawFirstSettings {
+               if _, ok := f.(*http2SettingsFrame); !ok {
+                       return http2ConnectionError(http2ErrCodeProtocol)
+               }
+               sc.sawFirstSettings = true
+       }
+
+       switch f := f.(type) {
+       case *http2SettingsFrame:
+               return sc.processSettings(f)
+       case *http2HeadersFrame:
+               return sc.processHeaders(f)
+       case *http2ContinuationFrame:
+               return sc.processContinuation(f)
+       case *http2WindowUpdateFrame:
+               return sc.processWindowUpdate(f)
+       case *http2PingFrame:
+               return sc.processPing(f)
+       case *http2DataFrame:
+               return sc.processData(f)
+       case *http2RSTStreamFrame:
+               return sc.processResetStream(f)
+       case *http2PriorityFrame:
+               return sc.processPriority(f)
+       case *http2PushPromiseFrame:
+
+               return http2ConnectionError(http2ErrCodeProtocol)
+       default:
+               sc.vlogf("http2: server ignoring frame: %v", f.Header())
+               return nil
+       }
+}
+
+func (sc *http2serverConn) processPing(f *http2PingFrame) error {
+       sc.serveG.check()
+       if f.IsAck() {
+
+               return nil
+       }
+       if f.StreamID != 0 {
+
+               return http2ConnectionError(http2ErrCodeProtocol)
+       }
+       sc.writeFrame(http2frameWriteMsg{write: http2writePingAck{f}})
+       return nil
+}
+
+func (sc *http2serverConn) processWindowUpdate(f *http2WindowUpdateFrame) error {
+       sc.serveG.check()
+       switch {
+       case f.StreamID != 0:
+               st := sc.streams[f.StreamID]
+               if st == nil {
+
+                       return nil
+               }
+               if !st.flow.add(int32(f.Increment)) {
+                       return http2StreamError{f.StreamID, http2ErrCodeFlowControl}
+               }
+       default:
+               if !sc.flow.add(int32(f.Increment)) {
+                       return http2goAwayFlowError{}
+               }
+       }
+       sc.scheduleFrameWrite()
+       return nil
+}
+
+func (sc *http2serverConn) processResetStream(f *http2RSTStreamFrame) error {
+       sc.serveG.check()
+
+       state, st := sc.state(f.StreamID)
+       if state == http2stateIdle {
+
+               return http2ConnectionError(http2ErrCodeProtocol)
+       }
+       if st != nil {
+               st.gotReset = true
+               sc.closeStream(st, http2StreamError{f.StreamID, f.ErrCode})
+       }
+       return nil
+}
+
+func (sc *http2serverConn) closeStream(st *http2stream, err error) {
+       sc.serveG.check()
+       if st.state == http2stateIdle || st.state == http2stateClosed {
+               panic(fmt.Sprintf("invariant; can't close stream in state %v", st.state))
+       }
+       st.state = http2stateClosed
+       sc.curOpenStreams--
+       if sc.curOpenStreams == 0 {
+               sc.setConnState(StateIdle)
+       }
+       delete(sc.streams, st.id)
+       if p := st.body; p != nil {
+               p.CloseWithError(err)
+       }
+       st.cw.Close()
+       sc.writeSched.forgetStream(st.id)
+}
+
+func (sc *http2serverConn) processSettings(f *http2SettingsFrame) error {
+       sc.serveG.check()
+       if f.IsAck() {
+               sc.unackedSettings--
+               if sc.unackedSettings < 0 {
+
+                       return http2ConnectionError(http2ErrCodeProtocol)
+               }
+               return nil
+       }
+       if err := f.ForeachSetting(sc.processSetting); err != nil {
+               return err
+       }
+       sc.needToSendSettingsAck = true
+       sc.scheduleFrameWrite()
+       return nil
+}
+
+func (sc *http2serverConn) processSetting(s http2Setting) error {
+       sc.serveG.check()
+       if err := s.Valid(); err != nil {
+               return err
+       }
+       if http2VerboseLogs {
+               sc.vlogf("http2: server processing setting %v", s)
+       }
+       switch s.ID {
+       case http2SettingHeaderTableSize:
+               sc.headerTableSize = s.Val
+               sc.hpackEncoder.SetMaxDynamicTableSize(s.Val)
+       case http2SettingEnablePush:
+               sc.pushEnabled = s.Val != 0
+       case http2SettingMaxConcurrentStreams:
+               sc.clientMaxStreams = s.Val
+       case http2SettingInitialWindowSize:
+               return sc.processSettingInitialWindowSize(s.Val)
+       case http2SettingMaxFrameSize:
+               sc.writeSched.maxFrameSize = s.Val
+       case http2SettingMaxHeaderListSize:
+               sc.peerMaxHeaderListSize = s.Val
+       default:
+
+               if http2VerboseLogs {
+                       sc.vlogf("http2: server ignoring unknown setting %v", s)
+               }
+       }
+       return nil
+}
+
+func (sc *http2serverConn) processSettingInitialWindowSize(val uint32) error {
+       sc.serveG.check()
+
+       old := sc.initialWindowSize
+       sc.initialWindowSize = int32(val)
+       growth := sc.initialWindowSize - old
+       for _, st := range sc.streams {
+               if !st.flow.add(growth) {
+
+                       return http2ConnectionError(http2ErrCodeFlowControl)
+               }
+       }
+       return nil
+}
+
+func (sc *http2serverConn) processData(f *http2DataFrame) error {
+       sc.serveG.check()
+
+       id := f.Header().StreamID
+       st, ok := sc.streams[id]
+       if !ok || st.state != http2stateOpen || st.gotTrailerHeader {
+
+               return http2StreamError{id, http2ErrCodeStreamClosed}
+       }
+       if st.body == nil {
+               panic("internal error: should have a body in this state")
+       }
+       data := f.Data()
+
+       if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes {
+               st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
+               return http2StreamError{id, http2ErrCodeStreamClosed}
+       }
+       if len(data) > 0 {
+
+               if int(st.inflow.available()) < len(data) {
+                       return http2StreamError{id, http2ErrCodeFlowControl}
+               }
+               st.inflow.take(int32(len(data)))
+               wrote, err := st.body.Write(data)
+               if err != nil {
+                       return http2StreamError{id, http2ErrCodeStreamClosed}
+               }
+               if wrote != len(data) {
+                       panic("internal error: bad Writer")
+               }
+               st.bodyBytes += int64(len(data))
+       }
+       if f.StreamEnded() {
+               st.endStream()
+       }
+       return nil
+}
+
+// endStream closes a Request.Body's pipe. It is called when a DATA
+// frame says a request body is over (or after trailers).
+func (st *http2stream) endStream() {
+       sc := st.sc
+       sc.serveG.check()
+
+       if st.declBodyBytes != -1 && st.declBodyBytes != st.bodyBytes {
+               st.body.CloseWithError(fmt.Errorf("request declared a Content-Length of %d but only wrote %d bytes",
+                       st.declBodyBytes, st.bodyBytes))
+       } else {
+               st.body.closeWithErrorAndCode(io.EOF, st.copyTrailersToHandlerRequest)
+               st.body.CloseWithError(io.EOF)
+       }
+       st.state = http2stateHalfClosedRemote
+}
+
+// copyTrailersToHandlerRequest is run in the Handler's goroutine in
+// its Request.Body.Read just before it gets io.EOF.
+func (st *http2stream) copyTrailersToHandlerRequest() {
+       for k, vv := range st.trailer {
+               if _, ok := st.reqTrailer[k]; ok {
+
+                       st.reqTrailer[k] = vv
+               }
+       }
+}
+
+func (sc *http2serverConn) processHeaders(f *http2HeadersFrame) error {
+       sc.serveG.check()
+       id := f.Header().StreamID
+       if sc.inGoAway {
+
+               return nil
+       }
+
+       if id%2 != 1 {
+               return http2ConnectionError(http2ErrCodeProtocol)
+       }
+
+       st := sc.streams[f.Header().StreamID]
+       if st != nil {
+               return st.processTrailerHeaders(f)
+       }
+
+       if id <= sc.maxStreamID || sc.req.stream != nil {
+               return http2ConnectionError(http2ErrCodeProtocol)
+       }
+
+       if id > sc.maxStreamID {
+               sc.maxStreamID = id
+       }
+       st = &http2stream{
+               sc:    sc,
+               id:    id,
+               state: http2stateOpen,
+       }
+       if f.StreamEnded() {
+               st.state = http2stateHalfClosedRemote
+       }
+       st.cw.Init()
+
+       st.flow.conn = &sc.flow
+       st.flow.add(sc.initialWindowSize)
+       st.inflow.conn = &sc.inflow
+       st.inflow.add(http2initialWindowSize)
+
+       sc.streams[id] = st
+       if f.HasPriority() {
+               http2adjustStreamPriority(sc.streams, st.id, f.Priority)
+       }
+       sc.curOpenStreams++
+       if sc.curOpenStreams == 1 {
+               sc.setConnState(StateActive)
+       }
+       sc.req = http2requestParam{
+               stream: st,
+               header: make(Header),
+       }
+       sc.hpackDecoder.SetEmitFunc(sc.onNewHeaderField)
+       sc.hpackDecoder.SetEmitEnabled(true)
+       return sc.processHeaderBlockFragment(st, f.HeaderBlockFragment(), f.HeadersEnded())
+}
+
+func (st *http2stream) processTrailerHeaders(f *http2HeadersFrame) error {
+       sc := st.sc
+       sc.serveG.check()
+       if st.gotTrailerHeader {
+               return http2ConnectionError(http2ErrCodeProtocol)
+       }
+       st.gotTrailerHeader = true
+       if !f.StreamEnded() {
+               return http2StreamError{st.id, http2ErrCodeProtocol}
+       }
+       sc.resetPendingRequest()
+       return st.processTrailerHeaderBlockFragment(f.HeaderBlockFragment(), f.HeadersEnded())
+}
+
+func (sc *http2serverConn) processContinuation(f *http2ContinuationFrame) error {
+       sc.serveG.check()
+       st := sc.streams[f.Header().StreamID]
+       if st.gotTrailerHeader {
+               return st.processTrailerHeaderBlockFragment(f.HeaderBlockFragment(), f.HeadersEnded())
+       }
+       return sc.processHeaderBlockFragment(st, f.HeaderBlockFragment(), f.HeadersEnded())
+}
+
+func (sc *http2serverConn) processHeaderBlockFragment(st *http2stream, frag []byte, end bool) error {
+       sc.serveG.check()
+       if _, err := sc.hpackDecoder.Write(frag); err != nil {
+               return http2ConnectionError(http2ErrCodeCompression)
+       }
+       if !end {
+               return nil
+       }
+       if err := sc.hpackDecoder.Close(); err != nil {
+               return http2ConnectionError(http2ErrCodeCompression)
+       }
+       defer sc.resetPendingRequest()
+       if sc.curOpenStreams > sc.advMaxStreams {
+
+               if sc.unackedSettings == 0 {
+
+                       return http2StreamError{st.id, http2ErrCodeProtocol}
+               }
+
+               return http2StreamError{st.id, http2ErrCodeRefusedStream}
+       }
+
+       rw, req, err := sc.newWriterAndRequest()
+       if err != nil {
+               return err
+       }
+       st.reqTrailer = req.Trailer
+       if st.reqTrailer != nil {
+               st.trailer = make(Header)
+       }
+       st.body = req.Body.(*http2requestBody).pipe
+       st.declBodyBytes = req.ContentLength
+
+       handler := sc.handler.ServeHTTP
+       if !sc.hpackDecoder.EmitEnabled() {
+
+               handler = http2handleHeaderListTooLong
+       }
+
+       go sc.runHandler(rw, req, handler)
+       return nil
+}
+
+func (st *http2stream) processTrailerHeaderBlockFragment(frag []byte, end bool) error {
+       sc := st.sc
+       sc.serveG.check()
+       sc.hpackDecoder.SetEmitFunc(st.onNewTrailerField)
+       if _, err := sc.hpackDecoder.Write(frag); err != nil {
+               return http2ConnectionError(http2ErrCodeCompression)
+       }
+       if !end {
+               return nil
+       }
+
+       rp := &sc.req
+       if rp.invalidHeader {
+               return http2StreamError{rp.stream.id, http2ErrCodeProtocol}
+       }
+
+       err := sc.hpackDecoder.Close()
+       st.endStream()
+       if err != nil {
+               return http2ConnectionError(http2ErrCodeCompression)
+       }
+       return nil
+}
+
+func (sc *http2serverConn) processPriority(f *http2PriorityFrame) error {
+       http2adjustStreamPriority(sc.streams, f.StreamID, f.http2PriorityParam)
+       return nil
+}
+
+func http2adjustStreamPriority(streams map[uint32]*http2stream, streamID uint32, priority http2PriorityParam) {
+       st, ok := streams[streamID]
+       if !ok {
+
+               return
+       }
+       st.weight = priority.Weight
+       parent := streams[priority.StreamDep]
+       if parent == st {
+
+               return
+       }
+
+       for piter := parent; piter != nil; piter = piter.parent {
+               if piter == st {
+                       parent.parent = st.parent
+                       break
+               }
+       }
+       st.parent = parent
+       if priority.Exclusive && (st.parent != nil || priority.StreamDep == 0) {
+               for _, openStream := range streams {
+                       if openStream != st && openStream.parent == st.parent {
+                               openStream.parent = st
+                       }
+               }
+       }
+}
+
+// resetPendingRequest zeros out all state related to a HEADERS frame
+// and its zero or more CONTINUATION frames sent to start a new
+// request.
+func (sc *http2serverConn) resetPendingRequest() {
+       sc.serveG.check()
+       sc.req = http2requestParam{}
+}
+
+func (sc *http2serverConn) newWriterAndRequest() (*http2responseWriter, *Request, error) {
+       sc.serveG.check()
+       rp := &sc.req
+
+       if rp.invalidHeader {
+               return nil, nil, http2StreamError{rp.stream.id, http2ErrCodeProtocol}
+       }
+
+       isConnect := rp.method == "CONNECT"
+       if isConnect {
+               if rp.path != "" || rp.scheme != "" || rp.authority == "" {
+                       return nil, nil, http2StreamError{rp.stream.id, http2ErrCodeProtocol}
+               }
+       } else if rp.method == "" || rp.path == "" ||
+               (rp.scheme != "https" && rp.scheme != "http") {
+
+               return nil, nil, http2StreamError{rp.stream.id, http2ErrCodeProtocol}
+       }
+
+       bodyOpen := rp.stream.state == http2stateOpen
+       if rp.method == "HEAD" && bodyOpen {
+
+               return nil, nil, http2StreamError{rp.stream.id, http2ErrCodeProtocol}
+       }
+       var tlsState *tls.ConnectionState // nil if not scheme https
+
+       if rp.scheme == "https" {
+               tlsState = sc.tlsState
+       }
+       authority := rp.authority
+       if authority == "" {
+               authority = rp.header.Get("Host")
+       }
+       needsContinue := rp.header.Get("Expect") == "100-continue"
+       if needsContinue {
+               rp.header.Del("Expect")
+       }
+
+       if cookies := rp.header["Cookie"]; len(cookies) > 1 {
+               rp.header.Set("Cookie", strings.Join(cookies, "; "))
+       }
+
+       // Setup Trailers
+       var trailer Header
+       for _, v := range rp.header["Trailer"] {
+               for _, key := range strings.Split(v, ",") {
+                       key = CanonicalHeaderKey(strings.TrimSpace(key))
+                       switch key {
+                       case "Transfer-Encoding", "Trailer", "Content-Length":
+
+                       default:
+                               if trailer == nil {
+                                       trailer = make(Header)
+                               }
+                               trailer[key] = nil
+                       }
+               }
+       }
+       delete(rp.header, "Trailer")
+
+       body := &http2requestBody{
+               conn:          sc,
+               stream:        rp.stream,
+               needsContinue: needsContinue,
+       }
+       var url_ *url.URL
+       var requestURI string
+       if isConnect {
+               url_ = &url.URL{Host: rp.authority}
+               requestURI = rp.authority
+       } else {
+               var err error
+               url_, err = url.ParseRequestURI(rp.path)
+               if err != nil {
+                       return nil, nil, http2StreamError{rp.stream.id, http2ErrCodeProtocol}
+               }
+               requestURI = rp.path
+       }
+       req := &Request{
+               Method:     rp.method,
+               URL:        url_,
+               RemoteAddr: sc.remoteAddrStr,
+               Header:     rp.header,
+               RequestURI: requestURI,
+               Proto:      "HTTP/2.0",
+               ProtoMajor: 2,
+               ProtoMinor: 0,
+               TLS:        tlsState,
+               Host:       authority,
+               Body:       body,
+               Trailer:    trailer,
+       }
+       if bodyOpen {
+               body.pipe = &http2pipe{
+                       b: &http2fixedBuffer{buf: make([]byte, http2initialWindowSize)},
+               }
+
+               if vv, ok := rp.header["Content-Length"]; ok {
+                       req.ContentLength, _ = strconv.ParseInt(vv[0], 10, 64)
+               } else {
+                       req.ContentLength = -1
+               }
+       }
+
+       rws := http2responseWriterStatePool.Get().(*http2responseWriterState)
+       bwSave := rws.bw
+       *rws = http2responseWriterState{}
+       rws.conn = sc
+       rws.bw = bwSave
+       rws.bw.Reset(http2chunkWriter{rws})
+       rws.stream = rp.stream
+       rws.req = req
+       rws.body = body
+
+       rw := &http2responseWriter{rws: rws}
+       return rw, req, nil
+}
+
+// Run on its own goroutine.
+func (sc *http2serverConn) runHandler(rw *http2responseWriter, req *Request, handler func(ResponseWriter, *Request)) {
+       didPanic := true
+       defer func() {
+               if didPanic {
+                       e := recover()
+                       // Same as net/http:
+                       const size = 64 << 10
+                       buf := make([]byte, size)
+                       buf = buf[:runtime.Stack(buf, false)]
+                       sc.writeFrameFromHandler(http2frameWriteMsg{
+                               write:  http2handlerPanicRST{rw.rws.stream.id},
+                               stream: rw.rws.stream,
+                       })
+                       sc.logf("http2: panic serving %v: %v\n%s", sc.conn.RemoteAddr(), e, buf)
+                       return
+               }
+               rw.handlerDone()
+       }()
+       handler(rw, req)
+       didPanic = false
+}
+
+func http2handleHeaderListTooLong(w ResponseWriter, r *Request) {
+       // 10.5.1 Limits on Header Block Size:
+       // .. "A server that receives a larger header block than it is
+       // willing to handle can send an HTTP 431 (Request Header Fields Too
+       // Large) status code"
+       const statusRequestHeaderFieldsTooLarge = 431 // only in Go 1.6+
+       w.WriteHeader(statusRequestHeaderFieldsTooLarge)
+       io.WriteString(w, "<h1>HTTP Error 431</h1><p>Request Header Field(s) Too Large</p>")
+}
+
+// called from handler goroutines.
+// h may be nil.
+func (sc *http2serverConn) writeHeaders(st *http2stream, headerData *http2writeResHeaders) error {
+       sc.serveG.checkNotOn()
+       var errc chan error
+       if headerData.h != nil {
+
+               errc = http2errChanPool.Get().(chan error)
+       }
+       if err := sc.writeFrameFromHandler(http2frameWriteMsg{
+               write:  headerData,
+               stream: st,
+               done:   errc,
+       }); err != nil {
+               return err
+       }
+       if errc != nil {
+               select {
+               case err := <-errc:
+                       http2errChanPool.Put(errc)
+                       return err
+               case <-sc.doneServing:
+                       return http2errClientDisconnected
+               case <-st.cw:
+                       return http2errStreamClosed
+               }
+       }
+       return nil
+}
+
+// called from handler goroutines.
+func (sc *http2serverConn) write100ContinueHeaders(st *http2stream) {
+       sc.writeFrameFromHandler(http2frameWriteMsg{
+               write:  http2write100ContinueHeadersFrame{st.id},
+               stream: st,
+       })
+}
+
+// A bodyReadMsg tells the server loop that the http.Handler read n
+// bytes of the DATA from the client on the given stream.
+type http2bodyReadMsg struct {
+       st *http2stream
+       n  int
+}
+
+// called from handler goroutines.
+// Notes that the handler for the given stream ID read n bytes of its body
+// and schedules flow control tokens to be sent.
+func (sc *http2serverConn) noteBodyReadFromHandler(st *http2stream, n int) {
+       sc.serveG.checkNotOn()
+       select {
+       case sc.bodyReadCh <- http2bodyReadMsg{st, n}:
+       case <-sc.doneServing:
+       }
+}
+
+func (sc *http2serverConn) noteBodyRead(st *http2stream, n int) {
+       sc.serveG.check()
+       sc.sendWindowUpdate(nil, n)
+       if st.state != http2stateHalfClosedRemote && st.state != http2stateClosed {
+
+               sc.sendWindowUpdate(st, n)
+       }
+}
+
+// st may be nil for conn-level
+func (sc *http2serverConn) sendWindowUpdate(st *http2stream, n int) {
+       sc.serveG.check()
+       // "The legal range for the increment to the flow control
+       // window is 1 to 2^31-1 (2,147,483,647) octets."
+       // A Go Read call on 64-bit machines could in theory read
+       // a larger Read than this. Very unlikely, but we handle it here
+       // rather than elsewhere for now.
+       const maxUint31 = 1<<31 - 1
+       for n >= maxUint31 {
+               sc.sendWindowUpdate32(st, maxUint31)
+               n -= maxUint31
+       }
+       sc.sendWindowUpdate32(st, int32(n))
+}
+
+// st may be nil for conn-level
+func (sc *http2serverConn) sendWindowUpdate32(st *http2stream, n int32) {
+       sc.serveG.check()
+       if n == 0 {
+               return
+       }
+       if n < 0 {
+               panic("negative update")
+       }
+       var streamID uint32
+       if st != nil {
+               streamID = st.id
+       }
+       sc.writeFrame(http2frameWriteMsg{
+               write:  http2writeWindowUpdate{streamID: streamID, n: uint32(n)},
+               stream: st,
+       })
+       var ok bool
+       if st == nil {
+               ok = sc.inflow.add(n)
+       } else {
+               ok = st.inflow.add(n)
+       }
+       if !ok {
+               panic("internal error; sent too many window updates without decrements?")
+       }
+}
+
+type http2requestBody struct {
+       stream        *http2stream
+       conn          *http2serverConn
+       closed        bool
+       pipe          *http2pipe // non-nil if we have a HTTP entity message body
+       needsContinue bool       // need to send a 100-continue
+}
+
+func (b *http2requestBody) Close() error {
+       if b.pipe != nil {
+               b.pipe.CloseWithError(http2errClosedBody)
+       }
+       b.closed = true
+       return nil
+}
+
+func (b *http2requestBody) Read(p []byte) (n int, err error) {
+       if b.needsContinue {
+               b.needsContinue = false
+               b.conn.write100ContinueHeaders(b.stream)
+       }
+       if b.pipe == nil {
+               return 0, io.EOF
+       }
+       n, err = b.pipe.Read(p)
+       if n > 0 {
+               b.conn.noteBodyReadFromHandler(b.stream, n)
+       }
+       return
+}
+
+// responseWriter is the http.ResponseWriter implementation.  It's
+// intentionally small (1 pointer wide) to minimize garbage.  The
+// responseWriterState pointer inside is zeroed at the end of a
+// request (in handlerDone) and calls on the responseWriter thereafter
+// simply crash (caller's mistake), but the much larger responseWriterState
+// and buffers are reused between multiple requests.
+type http2responseWriter struct {
+       rws *http2responseWriterState
+}
+
+// Optional http.ResponseWriter interfaces implemented.
+var (
+       _ CloseNotifier     = (*http2responseWriter)(nil)
+       _ Flusher           = (*http2responseWriter)(nil)
+       _ http2stringWriter = (*http2responseWriter)(nil)
+)
+
+type http2responseWriterState struct {
+       // immutable within a request:
+       stream *http2stream
+       req    *Request
+       body   *http2requestBody // to close at end of request, if DATA frames didn't
+       conn   *http2serverConn
+
+       // TODO: adjust buffer writing sizes based on server config, frame size updates from peer, etc
+       bw *bufio.Writer // writing to a chunkWriter{this *responseWriterState}
+
+       // mutated by http.Handler goroutine:
+       handlerHeader Header   // nil until called
+       snapHeader    Header   // snapshot of handlerHeader at WriteHeader time
+       trailers      []string // set in writeChunk
+       status        int      // status code passed to WriteHeader
+       wroteHeader   bool     // WriteHeader called (explicitly or implicitly). Not necessarily sent to user yet.
+       sentHeader    bool     // have we sent the header frame?
+       handlerDone   bool     // handler has finished
+
+       sentContentLen int64 // non-zero if handler set a Content-Length header
+       wroteBytes     int64
+
+       closeNotifierMu sync.Mutex // guards closeNotifierCh
+       closeNotifierCh chan bool  // nil until first used
+}
+
+type http2chunkWriter struct{ rws *http2responseWriterState }
+
+func (cw http2chunkWriter) Write(p []byte) (n int, err error) { return cw.rws.writeChunk(p) }
+
+func (rws *http2responseWriterState) hasTrailers() bool { return len(rws.trailers) != 0 }
+
+// declareTrailer is called for each Trailer header when the
+// response header is written. It notes that a header will need to be
+// written in the trailers at the end of the response.
+func (rws *http2responseWriterState) declareTrailer(k string) {
+       k = CanonicalHeaderKey(k)
+       switch k {
+       case "Transfer-Encoding", "Content-Length", "Trailer":
+
+               return
+       }
+       rws.trailers = append(rws.trailers, k)
+}
+
+// writeChunk writes chunks from the bufio.Writer. But because
+// bufio.Writer may bypass its chunking, sometimes p may be
+// arbitrarily large.
+//
+// writeChunk is also responsible (on the first chunk) for sending the
+// HEADER response.
+func (rws *http2responseWriterState) writeChunk(p []byte) (n int, err error) {
+       if !rws.wroteHeader {
+               rws.writeHeader(200)
+       }
+
+       isHeadResp := rws.req.Method == "HEAD"
+       if !rws.sentHeader {
+               rws.sentHeader = true
+               var ctype, clen string
+               if clen = rws.snapHeader.Get("Content-Length"); clen != "" {
+                       rws.snapHeader.Del("Content-Length")
+                       clen64, err := strconv.ParseInt(clen, 10, 64)
+                       if err == nil && clen64 >= 0 {
+                               rws.sentContentLen = clen64
+                       } else {
+                               clen = ""
+                       }
+               }
+               if clen == "" && rws.handlerDone && http2bodyAllowedForStatus(rws.status) && (len(p) > 0 || !isHeadResp) {
+                       clen = strconv.Itoa(len(p))
+               }
+               _, hasContentType := rws.snapHeader["Content-Type"]
+               if !hasContentType && http2bodyAllowedForStatus(rws.status) {
+                       ctype = DetectContentType(p)
+               }
+               var date string
+               if _, ok := rws.snapHeader["Date"]; !ok {
+
+                       date = time.Now().UTC().Format(TimeFormat)
+               }
+
+               for _, v := range rws.snapHeader["Trailer"] {
+                       http2foreachHeaderElement(v, rws.declareTrailer)
+               }
+
+               endStream := (rws.handlerDone && !rws.hasTrailers() && len(p) == 0) || isHeadResp
+               err = rws.conn.writeHeaders(rws.stream, &http2writeResHeaders{
+                       streamID:      rws.stream.id,
+                       httpResCode:   rws.status,
+                       h:             rws.snapHeader,
+                       endStream:     endStream,
+                       contentType:   ctype,
+                       contentLength: clen,
+                       date:          date,
+               })
+               if err != nil {
+                       return 0, err
+               }
+               if endStream {
+                       return 0, nil
+               }
+       }
+       if isHeadResp {
+               return len(p), nil
+       }
+       if len(p) == 0 && !rws.handlerDone {
+               return 0, nil
+       }
+
+       endStream := rws.handlerDone && !rws.hasTrailers()
+       if len(p) > 0 || endStream {
+
+               if err := rws.conn.writeDataFromHandler(rws.stream, p, endStream); err != nil {
+                       return 0, err
+               }
+       }
+
+       if rws.handlerDone && rws.hasTrailers() {
+               err = rws.conn.writeHeaders(rws.stream, &http2writeResHeaders{
+                       streamID:  rws.stream.id,
+                       h:         rws.handlerHeader,
+                       trailers:  rws.trailers,
+                       endStream: true,
+               })
+               return len(p), err
+       }
+       return len(p), nil
+}
+
+func (w *http2responseWriter) Flush() {
+       rws := w.rws
+       if rws == nil {
+               panic("Header called after Handler finished")
+       }
+       if rws.bw.Buffered() > 0 {
+               if err := rws.bw.Flush(); err != nil {
+
+                       return
+               }
+       } else {
+
+               rws.writeChunk(nil)
+       }
+}
+
+func (w *http2responseWriter) CloseNotify() <-chan bool {
+       rws := w.rws
+       if rws == nil {
+               panic("CloseNotify called after Handler finished")
+       }
+       rws.closeNotifierMu.Lock()
+       ch := rws.closeNotifierCh
+       if ch == nil {
+               ch = make(chan bool, 1)
+               rws.closeNotifierCh = ch
+               go func() {
+                       rws.stream.cw.Wait()
+                       ch <- true
+               }()
+       }
+       rws.closeNotifierMu.Unlock()
+       return ch
+}
+
+func (w *http2responseWriter) Header() Header {
+       rws := w.rws
+       if rws == nil {
+               panic("Header called after Handler finished")
+       }
+       if rws.handlerHeader == nil {
+               rws.handlerHeader = make(Header)
+       }
+       return rws.handlerHeader
+}
+
+func (w *http2responseWriter) WriteHeader(code int) {
+       rws := w.rws
+       if rws == nil {
+               panic("WriteHeader called after Handler finished")
+       }
+       rws.writeHeader(code)
+}
+
+func (rws *http2responseWriterState) writeHeader(code int) {
+       if !rws.wroteHeader {
+               rws.wroteHeader = true
+               rws.status = code
+               if len(rws.handlerHeader) > 0 {
+                       rws.snapHeader = http2cloneHeader(rws.handlerHeader)
+               }
+       }
+}
+
+func http2cloneHeader(h Header) Header {
+       h2 := make(Header, len(h))
+       for k, vv := range h {
+               vv2 := make([]string, len(vv))
+               copy(vv2, vv)
+               h2[k] = vv2
+       }
+       return h2
+}
+
+// The Life Of A Write is like this:
+//
+// * Handler calls w.Write or w.WriteString ->
+// * -> rws.bw (*bufio.Writer) ->
+// * (Handler migth call Flush)
+// * -> chunkWriter{rws}
+// * -> responseWriterState.writeChunk(p []byte)
+// * -> responseWriterState.writeChunk (most of the magic; see comment there)
+func (w *http2responseWriter) Write(p []byte) (n int, err error) {
+       return w.write(len(p), p, "")
+}
+
+func (w *http2responseWriter) WriteString(s string) (n int, err error) {
+       return w.write(len(s), nil, s)
+}
+
+// either dataB or dataS is non-zero.
+func (w *http2responseWriter) write(lenData int, dataB []byte, dataS string) (n int, err error) {
+       rws := w.rws
+       if rws == nil {
+               panic("Write called after Handler finished")
+       }
+       if !rws.wroteHeader {
+               w.WriteHeader(200)
+       }
+       if !http2bodyAllowedForStatus(rws.status) {
+               return 0, ErrBodyNotAllowed
+       }
+       rws.wroteBytes += int64(len(dataB)) + int64(len(dataS))
+       if rws.sentContentLen != 0 && rws.wroteBytes > rws.sentContentLen {
+
+               return 0, errors.New("http2: handler wrote more than declared Content-Length")
+       }
+
+       if dataB != nil {
+               return rws.bw.Write(dataB)
+       } else {
+               return rws.bw.WriteString(dataS)
+       }
+}
+
+func (w *http2responseWriter) handlerDone() {
+       rws := w.rws
+       rws.handlerDone = true
+       w.Flush()
+       w.rws = nil
+       http2responseWriterStatePool.Put(rws)
+}
+
+// foreachHeaderElement splits v according to the "#rule" construction
+// in RFC 2616 section 2.1 and calls fn for each non-empty element.
+func http2foreachHeaderElement(v string, fn func(string)) {
+       v = textproto.TrimString(v)
+       if v == "" {
+               return
+       }
+       if !strings.Contains(v, ",") {
+               fn(v)
+               return
+       }
+       for _, f := range strings.Split(v, ",") {
+               if f = textproto.TrimString(f); f != "" {
+                       fn(f)
+               }
+       }
+}
+
+const (
+       // transportDefaultConnFlow is how many connection-level flow control
+       // tokens we give the server at start-up, past the default 64k.
+       http2transportDefaultConnFlow = 1 << 30
+
+       // transportDefaultStreamFlow is how many stream-level flow
+       // control tokens we announce to the peer, and how many bytes
+       // we buffer per stream.
+       http2transportDefaultStreamFlow = 4 << 20
+
+       // transportDefaultStreamMinRefresh is the minimum number of bytes we'll send
+       // a stream-level WINDOW_UPDATE for at a time.
+       http2transportDefaultStreamMinRefresh = 4 << 10
+
+       http2defaultUserAgent = "Go-http-client/2.0"
+)
+
+// Transport is an HTTP/2 Transport.
+//
+// A Transport internally caches connections to servers. It is safe
+// for concurrent use by multiple goroutines.
+type http2Transport struct {
+       // DialTLS specifies an optional dial function for creating
+       // TLS connections for requests.
+       //
+       // If DialTLS is nil, tls.Dial is used.
+       //
+       // If the returned net.Conn has a ConnectionState method like tls.Conn,
+       // it will be used to set http.Response.TLS.
+       DialTLS func(network, addr string, cfg *tls.Config) (net.Conn, error)
+
+       // TLSClientConfig specifies the TLS configuration to use with
+       // tls.Client. If nil, the default configuration is used.
+       TLSClientConfig *tls.Config
+
+       // ConnPool optionally specifies an alternate connection pool to use.
+       // If nil, the default is used.
+       ConnPool http2ClientConnPool
+
+       // DisableCompression, if true, prevents the Transport from
+       // requesting compression with an "Accept-Encoding: gzip"
+       // request header when the Request contains no existing
+       // Accept-Encoding value. If the Transport requests gzip on
+       // its own and gets a gzipped response, it's transparently
+       // decoded in the Response.Body. However, if the user
+       // explicitly requested gzip it is not automatically
+       // uncompressed.
+       DisableCompression bool
+
+       // MaxHeaderListSize is the http2 SETTINGS_MAX_HEADER_LIST_SIZE to
+       // send in the initial settings frame. It is how many bytes
+       // of response headers are allow. Unlike the http2 spec, zero here
+       // means to use a default limit (currently 10MB). If you actually
+       // want to advertise an ulimited value to the peer, Transport
+       // interprets the highest possible value here (0xffffffff or 1<<32-1)
+       // to mean no limit.
+       MaxHeaderListSize uint32
+
+       // t1, if non-nil, is the standard library Transport using
+       // this transport. Its settings are used (but not its
+       // RoundTrip method, etc).
+       t1 *Transport
+
+       connPoolOnce  sync.Once
+       connPoolOrDef http2ClientConnPool // non-nil version of ConnPool
+}
+
+func (t *http2Transport) maxHeaderListSize() uint32 {
+       if t.MaxHeaderListSize == 0 {
+               return 10 << 20
+       }
+       if t.MaxHeaderListSize == 0xffffffff {
+               return 0
+       }
+       return t.MaxHeaderListSize
+}
+
+func (t *http2Transport) disableCompression() bool {
+       return t.DisableCompression || (t.t1 != nil && t.t1.DisableCompression)
+}
+
+var http2errTransportVersion = errors.New("http2: ConfigureTransport is only supported starting at Go 1.6")
+
+// ConfigureTransport configures a net/http HTTP/1 Transport to use HTTP/2.
+// It requires Go 1.6 or later and returns an error if the net/http package is too old
+// or if t1 has already been HTTP/2-enabled.
+func http2ConfigureTransport(t1 *Transport) error {
+       _, err := http2configureTransport(t1)
+       return err
+}
+
+func (t *http2Transport) connPool() http2ClientConnPool {
+       t.connPoolOnce.Do(t.initConnPool)
+       return t.connPoolOrDef
+}
+
+func (t *http2Transport) initConnPool() {
+       if t.ConnPool != nil {
+               t.connPoolOrDef = t.ConnPool
+       } else {
+               t.connPoolOrDef = &http2clientConnPool{t: t}
+       }
+}
+
+// ClientConn is the state of a single HTTP/2 client connection to an
+// HTTP/2 server.
+type http2ClientConn struct {
+       t        *http2Transport
+       tconn    net.Conn             // usually *tls.Conn, except specialized impls
+       tlsState *tls.ConnectionState // nil only for specialized impls
+
+       // readLoop goroutine fields:
+       readerDone chan struct{} // closed on error
+       readerErr  error         // set before readerDone is closed
+
+       mu           sync.Mutex // guards following
+       cond         *sync.Cond // hold mu; broadcast on flow/closed changes
+       flow         http2flow  // our conn-level flow control quota (cs.flow is per stream)
+       inflow       http2flow  // peer's conn-level flow control
+       closed       bool
+       goAway       *http2GoAwayFrame             // if non-nil, the GoAwayFrame we received
+       streams      map[uint32]*http2clientStream // client-initiated
+       nextStreamID uint32
+       bw           *bufio.Writer
+       br           *bufio.Reader
+       fr           *http2Framer
+       // Settings from peer:
+       maxFrameSize         uint32
+       maxConcurrentStreams uint32
+       initialWindowSize    uint32
+       hbuf                 bytes.Buffer // HPACK encoder writes into this
+       henc                 *hpack.Encoder
+       freeBuf              [][]byte
+
+       wmu  sync.Mutex // held while writing; acquire AFTER mu if holding both
+       werr error      // first write error that has occurred
+}
+
+// clientStream is the state for a single HTTP/2 stream. One of these
+// is created for each Transport.RoundTrip call.
+type http2clientStream struct {
+       cc            *http2ClientConn
+       req           *Request
+       ID            uint32
+       resc          chan http2resAndError
+       bufPipe       http2pipe // buffered pipe with the flow-controlled response payload
+       requestedGzip bool
+
+       flow        http2flow // guarded by cc.mu
+       inflow      http2flow // guarded by cc.mu
+       bytesRemain int64     // -1 means unknown; owned by transportResponseBody.Read
+       readErr     error     // sticky read error; owned by transportResponseBody.Read
+       stopReqBody error     // if non-nil, stop writing req body; guarded by cc.mu
+
+       peerReset chan struct{} // closed on peer reset
+       resetErr  error         // populated before peerReset is closed
+
+       done chan struct{} // closed when stream remove from cc.streams map; close calls guarded by cc.mu
+
+       // owned by clientConnReadLoop:
+       pastHeaders  bool // got HEADERS w/ END_HEADERS
+       pastTrailers bool // got second HEADERS frame w/ END_HEADERS
+
+       trailer    Header  // accumulated trailers
+       resTrailer *Header // client's Response.Trailer
+}
+
+// awaitRequestCancel runs in its own goroutine and waits for the user
+// to either cancel a RoundTrip request (using the provided
+// Request.Cancel channel), or for the request to be done (any way it
+// might be removed from the cc.streams map: peer reset, successful
+// completion, TCP connection breakage, etc)
+func (cs *http2clientStream) awaitRequestCancel(cancel <-chan struct{}) {
+       if cancel == nil {
+               return
+       }
+       select {
+       case <-cancel:
+               cs.bufPipe.CloseWithError(http2errRequestCanceled)
+               cs.cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
+       case <-cs.done:
+       }
+}
+
+// checkReset reports any error sent in a RST_STREAM frame by the
+// server.
+func (cs *http2clientStream) checkReset() error {
+       select {
+       case <-cs.peerReset:
+               return cs.resetErr
+       default:
+               return nil
+       }
+}
+
+func (cs *http2clientStream) abortRequestBodyWrite(err error) {
+       if err == nil {
+               panic("nil error")
+       }
+       cc := cs.cc
+       cc.mu.Lock()
+       cs.stopReqBody = err
+       cc.cond.Broadcast()
+       cc.mu.Unlock()
+}
+
+type http2stickyErrWriter struct {
+       w   io.Writer
+       err *error
+}
+
+func (sew http2stickyErrWriter) Write(p []byte) (n int, err error) {
+       if *sew.err != nil {
+               return 0, *sew.err
+       }
+       n, err = sew.w.Write(p)
+       *sew.err = err
+       return
+}
+
+var http2ErrNoCachedConn = errors.New("http2: no cached connection was available")
+
+// RoundTripOpt are options for the Transport.RoundTripOpt method.
+type http2RoundTripOpt struct {
+       // OnlyCachedConn controls whether RoundTripOpt may
+       // create a new TCP connection. If set true and
+       // no cached connection is available, RoundTripOpt
+       // will return ErrNoCachedConn.
+       OnlyCachedConn bool
+}
+
+func (t *http2Transport) RoundTrip(req *Request) (*Response, error) {
+       return t.RoundTripOpt(req, http2RoundTripOpt{})
+}
+
+// authorityAddr returns a given authority (a host/IP, or host:port / ip:port)
+// and returns a host:port. The port 443 is added if needed.
+func http2authorityAddr(authority string) (addr string) {
+       if _, _, err := net.SplitHostPort(authority); err == nil {
+               return authority
+       }
+       return net.JoinHostPort(authority, "443")
+}
+
+// RoundTripOpt is like RoundTrip, but takes options.
+func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Response, error) {
+       if req.URL.Scheme != "https" {
+               return nil, errors.New("http2: unsupported scheme")
+       }
+
+       addr := http2authorityAddr(req.URL.Host)
+       for {
+               cc, err := t.connPool().GetClientConn(req, addr)
+               if err != nil {
+                       t.vlogf("http2: Transport failed to get client conn for %s: %v", addr, err)
+                       return nil, err
+               }
+               res, err := cc.RoundTrip(req)
+               if http2shouldRetryRequest(req, err) {
+                       continue
+               }
+               if err != nil {
+                       t.vlogf("RoundTrip failure: %v", err)
+                       return nil, err
+               }
+               return res, nil
+       }
+}
+
+// CloseIdleConnections closes any connections which were previously
+// connected from previous requests but are now sitting idle.
+// It does not interrupt any connections currently in use.
+func (t *http2Transport) CloseIdleConnections() {
+       if cp, ok := t.connPool().(*http2clientConnPool); ok {
+               cp.closeIdleConnections()
+       }
+}
+
+var (
+       http2errClientConnClosed   = errors.New("http2: client conn is closed")
+       http2errClientConnUnusable = errors.New("http2: client conn not usable")
+)
+
+func http2shouldRetryRequest(req *Request, err error) bool {
+
+       return err == http2errClientConnUnusable
+}
+
+func (t *http2Transport) dialClientConn(addr string) (*http2ClientConn, error) {
+       host, _, err := net.SplitHostPort(addr)
+       if err != nil {
+               return nil, err
+       }
+       tconn, err := t.dialTLS()("tcp", addr, t.newTLSConfig(host))
+       if err != nil {
+               return nil, err
+       }
+       return t.NewClientConn(tconn)
+}
+
+func (t *http2Transport) newTLSConfig(host string) *tls.Config {
+       cfg := new(tls.Config)
+       if t.TLSClientConfig != nil {
+               *cfg = *t.TLSClientConfig
+       }
+       cfg.NextProtos = []string{http2NextProtoTLS}
+       cfg.ServerName = host
+       return cfg
+}
+
+func (t *http2Transport) dialTLS() func(string, string, *tls.Config) (net.Conn, error) {
+       if t.DialTLS != nil {
+               return t.DialTLS
+       }
+       return t.dialTLSDefault
+}
+
+func (t *http2Transport) dialTLSDefault(network, addr string, cfg *tls.Config) (net.Conn, error) {
+       cn, err := tls.Dial(network, addr, cfg)
+       if err != nil {
+               return nil, err
+       }
+       if err := cn.Handshake(); err != nil {
+               return nil, err
+       }
+       if !cfg.InsecureSkipVerify {
+               if err := cn.VerifyHostname(cfg.ServerName); err != nil {
+                       return nil, err
+               }
+       }
+       state := cn.ConnectionState()
+       if p := state.NegotiatedProtocol; p != http2NextProtoTLS {
+               return nil, fmt.Errorf("http2: unexpected ALPN protocol %q; want %q", p, http2NextProtoTLS)
+       }
+       if !state.NegotiatedProtocolIsMutual {
+               return nil, errors.New("http2: could not negotiate protocol mutually")
+       }
+       return cn, nil
+}
+
+// disableKeepAlives reports whether connections should be closed as
+// soon as possible after handling the first request.
+func (t *http2Transport) disableKeepAlives() bool {
+       return t.t1 != nil && t.t1.DisableKeepAlives
+}
+
+func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
+       if http2VerboseLogs {
+               t.vlogf("http2: Transport creating client conn to %v", c.RemoteAddr())
+       }
+       if _, err := c.Write(http2clientPreface); err != nil {
+               t.vlogf("client preface write error: %v", err)
+               return nil, err
+       }
+
+       cc := &http2ClientConn{
+               t:                    t,
+               tconn:                c,
+               readerDone:           make(chan struct{}),
+               nextStreamID:         1,
+               maxFrameSize:         16 << 10,
+               initialWindowSize:    65535,
+               maxConcurrentStreams: 1000,
+               streams:              make(map[uint32]*http2clientStream),
+       }
+       cc.cond = sync.NewCond(&cc.mu)
+       cc.flow.add(int32(http2initialWindowSize))
+
+       cc.bw = bufio.NewWriter(http2stickyErrWriter{c, &cc.werr})
+       cc.br = bufio.NewReader(c)
+       cc.fr = http2NewFramer(cc.bw, cc.br)
+
+       cc.henc = hpack.NewEncoder(&cc.hbuf)
+
+       type connectionStater interface {
+               ConnectionState() tls.ConnectionState
+       }
+       if cs, ok := c.(connectionStater); ok {
+               state := cs.ConnectionState()
+               cc.tlsState = &state
+       }
+
+       initialSettings := []http2Setting{
+               http2Setting{ID: http2SettingEnablePush, Val: 0},
+               http2Setting{ID: http2SettingInitialWindowSize, Val: http2transportDefaultStreamFlow},
+       }
+       if max := t.maxHeaderListSize(); max != 0 {
+               initialSettings = append(initialSettings, http2Setting{ID: http2SettingMaxHeaderListSize, Val: max})
+       }
+       cc.fr.WriteSettings(initialSettings...)
+       cc.fr.WriteWindowUpdate(0, http2transportDefaultConnFlow)
+       cc.inflow.add(http2transportDefaultConnFlow + http2initialWindowSize)
+       cc.bw.Flush()
+       if cc.werr != nil {
+               return nil, cc.werr
+       }
+
+       f, err := cc.fr.ReadFrame()
+       if err != nil {
+               return nil, err
+       }
+       sf, ok := f.(*http2SettingsFrame)
+       if !ok {
+               return nil, fmt.Errorf("expected settings frame, got: %T", f)
+       }
+       cc.fr.WriteSettingsAck()
+       cc.bw.Flush()
+
+       sf.ForeachSetting(func(s http2Setting) error {
+               switch s.ID {
+               case http2SettingMaxFrameSize:
+                       cc.maxFrameSize = s.Val
+               case http2SettingMaxConcurrentStreams:
+                       cc.maxConcurrentStreams = s.Val
+               case http2SettingInitialWindowSize:
+                       cc.initialWindowSize = s.Val
+               default:
+
+                       t.vlogf("Unhandled Setting: %v", s)
+               }
+               return nil
+       })
+
+       go cc.readLoop()
+       return cc, nil
+}
+
+func (cc *http2ClientConn) setGoAway(f *http2GoAwayFrame) {
+       cc.mu.Lock()
+       defer cc.mu.Unlock()
+       cc.goAway = f
+}
+
+func (cc *http2ClientConn) CanTakeNewRequest() bool {
+       cc.mu.Lock()
+       defer cc.mu.Unlock()
+       return cc.canTakeNewRequestLocked()
+}
+
+func (cc *http2ClientConn) canTakeNewRequestLocked() bool {
+       return cc.goAway == nil && !cc.closed &&
+               int64(len(cc.streams)+1) < int64(cc.maxConcurrentStreams) &&
+               cc.nextStreamID < 2147483647
+}
+
+func (cc *http2ClientConn) closeIfIdle() {
+       cc.mu.Lock()
+       if len(cc.streams) > 0 {
+               cc.mu.Unlock()
+               return
+       }
+       cc.closed = true
+
+       cc.mu.Unlock()
+
+       cc.tconn.Close()
+}
+
+const http2maxAllocFrameSize = 512 << 10
+
+// frameBuffer returns a scratch buffer suitable for writing DATA frames.
+// They're capped at the min of the peer's max frame size or 512KB
+// (kinda arbitrarily), but definitely capped so we don't allocate 4GB
+// bufers.
+func (cc *http2ClientConn) frameScratchBuffer() []byte {
+       cc.mu.Lock()
+       size := cc.maxFrameSize
+       if size > http2maxAllocFrameSize {
+               size = http2maxAllocFrameSize
+       }
+       for i, buf := range cc.freeBuf {
+               if len(buf) >= int(size) {
+                       cc.freeBuf[i] = nil
+                       cc.mu.Unlock()
+                       return buf[:size]
+               }
+       }
+       cc.mu.Unlock()
+       return make([]byte, size)
+}
+
+func (cc *http2ClientConn) putFrameScratchBuffer(buf []byte) {
+       cc.mu.Lock()
+       defer cc.mu.Unlock()
+       const maxBufs = 4 // arbitrary; 4 concurrent requests per conn? investigate.
+       if len(cc.freeBuf) < maxBufs {
+               cc.freeBuf = append(cc.freeBuf, buf)
+               return
+       }
+       for i, old := range cc.freeBuf {
+               if old == nil {
+                       cc.freeBuf[i] = buf
+                       return
+               }
+       }
+
+}
+
+// errRequestCanceled is a copy of net/http's errRequestCanceled because it's not
+// exported. At least they'll be DeepEqual for h1-vs-h2 comparisons tests.
+var http2errRequestCanceled = errors.New("net/http: request canceled")
+
+func http2commaSeparatedTrailers(req *Request) (string, error) {
+       keys := make([]string, 0, len(req.Trailer))
+       for k := range req.Trailer {
+               k = CanonicalHeaderKey(k)
+               switch k {
+               case "Transfer-Encoding", "Trailer", "Content-Length":
+                       return "", &http2badStringError{"invalid Trailer key", k}
+               }
+               keys = append(keys, k)
+       }
+       if len(keys) > 0 {
+               sort.Strings(keys)
+
+               return strings.Join(keys, ","), nil
+       }
+       return "", nil
+}
+
+func (cc *http2ClientConn) responseHeaderTimeout() time.Duration {
+       if cc.t.t1 != nil {
+               return cc.t.t1.ResponseHeaderTimeout
+       }
+
+       return 0
+}
+
+func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
+       trailers, err := http2commaSeparatedTrailers(req)
+       if err != nil {
+               return nil, err
+       }
+       hasTrailers := trailers != ""
+
+       var body io.Reader = req.Body
+       contentLen := req.ContentLength
+       if req.Body != nil && contentLen == 0 {
+               // Test to see if it's actually zero or just unset.
+               var buf [1]byte
+               n, rerr := io.ReadFull(body, buf[:])
+               if rerr != nil && rerr != io.EOF {
+                       contentLen = -1
+                       body = http2errorReader{rerr}
+               } else if n == 1 {
+
+                       contentLen = -1
+                       body = io.MultiReader(bytes.NewReader(buf[:]), body)
+               } else {
+
+                       body = nil
+               }
+       }
+
+       cc.mu.Lock()
+       if cc.closed || !cc.canTakeNewRequestLocked() {
+               cc.mu.Unlock()
+               return nil, http2errClientConnUnusable
+       }
+
+       cs := cc.newStream()
+       cs.req = req
+       hasBody := body != nil
+
+       if !cc.t.disableCompression() &&
+               req.Header.Get("Accept-Encoding") == "" &&
+               req.Header.Get("Range") == "" &&
+               req.Method != "HEAD" {
+
+               cs.requestedGzip = true
+       }
+
+       hdrs := cc.encodeHeaders(req, cs.requestedGzip, trailers, contentLen)
+       cc.wmu.Lock()
+       endStream := !hasBody && !hasTrailers
+       werr := cc.writeHeaders(cs.ID, endStream, hdrs)
+       cc.wmu.Unlock()
+       cc.mu.Unlock()
+
+       if werr != nil {
+               if hasBody {
+                       req.Body.Close()
+               }
+               cc.forgetStreamID(cs.ID)
+
+               return nil, werr
+       }
+
+       var respHeaderTimer <-chan time.Time
+       var bodyCopyErrc chan error // result of body copy
+       if hasBody {
+               bodyCopyErrc = make(chan error, 1)
+               go func() {
+                       bodyCopyErrc <- cs.writeRequestBody(body, req.Body)
+               }()
+       } else {
+               if d := cc.responseHeaderTimeout(); d != 0 {
+                       timer := time.NewTimer(d)
+                       defer timer.Stop()
+                       respHeaderTimer = timer.C
+               }
+       }
+
+       readLoopResCh := cs.resc
+       requestCanceledCh := http2requestCancel(req)
+       bodyWritten := false
+
+       for {
+               select {
+               case re := <-readLoopResCh:
+                       res := re.res
+                       if re.err != nil || res.StatusCode > 299 {
+
+                               cs.abortRequestBodyWrite(http2errStopReqBodyWrite)
+                       }
+                       if re.err != nil {
+                               cc.forgetStreamID(cs.ID)
+                               return nil, re.err
+                       }
+                       res.Request = req
+                       res.TLS = cc.tlsState
+                       return res, nil
+               case <-respHeaderTimer:
+                       cc.forgetStreamID(cs.ID)
+                       if !hasBody || bodyWritten {
+                               cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
+                       } else {
+                               cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
+                       }
+                       return nil, http2errTimeout
+               case <-requestCanceledCh:
+                       cc.forgetStreamID(cs.ID)
+                       if !hasBody || bodyWritten {
+                               cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
+                       } else {
+                               cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
+                       }
+                       return nil, http2errRequestCanceled
+               case <-cs.peerReset:
+
+                       return nil, cs.resetErr
+               case err := <-bodyCopyErrc:
+                       if err != nil {
+                               return nil, err
+                       }
+                       bodyWritten = true
+                       if d := cc.responseHeaderTimeout(); d != 0 {
+                               timer := time.NewTimer(d)
+                               defer timer.Stop()
+                               respHeaderTimer = timer.C
+                       }
+               }
+       }
+}
+
+// requires cc.wmu be held
+func (cc *http2ClientConn) writeHeaders(streamID uint32, endStream bool, hdrs []byte) error {
+       first := true
+       frameSize := int(cc.maxFrameSize)
+       for len(hdrs) > 0 && cc.werr == nil {
+               chunk := hdrs
+               if len(chunk) > frameSize {
+                       chunk = chunk[:frameSize]
+               }
+               hdrs = hdrs[len(chunk):]
+               endHeaders := len(hdrs) == 0
+               if first {
+                       cc.fr.WriteHeaders(http2HeadersFrameParam{
+                               StreamID:      streamID,
+                               BlockFragment: chunk,
+                               EndStream:     endStream,
+                               EndHeaders:    endHeaders,
+                       })
+                       first = false
+               } else {
+                       cc.fr.WriteContinuation(streamID, endHeaders, chunk)
+               }
+       }
+
+       cc.bw.Flush()
+       return cc.werr
+}
+
+// internal error values; they don't escape to callers
+var (
+       // abort request body write; don't send cancel
+       http2errStopReqBodyWrite = errors.New("http2: aborting request body write")
+
+       // abort request body write, but send stream reset of cancel.
+       http2errStopReqBodyWriteAndCancel = errors.New("http2: canceling request")
+)
+
+func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Closer) (err error) {
+       cc := cs.cc
+       sentEnd := false
+       buf := cc.frameScratchBuffer()
+       defer cc.putFrameScratchBuffer(buf)
+
+       defer func() {
+
+               cerr := bodyCloser.Close()
+               if err == nil {
+                       err = cerr
+               }
+       }()
+
+       req := cs.req
+       hasTrailers := req.Trailer != nil
+
+       var sawEOF bool
+       for !sawEOF {
+               n, err := body.Read(buf)
+               if err == io.EOF {
+                       sawEOF = true
+                       err = nil
+               } else if err != nil {
+                       return err
+               }
+
+               remain := buf[:n]
+               for len(remain) > 0 && err == nil {
+                       var allowed int32
+                       allowed, err = cs.awaitFlowControl(len(remain))
+                       switch {
+                       case err == http2errStopReqBodyWrite:
+                               return err
+                       case err == http2errStopReqBodyWriteAndCancel:
+                               cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
+                               return err
+                       case err != nil:
+                               return err
+                       }
+                       cc.wmu.Lock()
+                       data := remain[:allowed]
+                       remain = remain[allowed:]
+                       sentEnd = sawEOF && len(remain) == 0 && !hasTrailers
+                       err = cc.fr.WriteData(cs.ID, sentEnd, data)
+                       if err == nil {
+
+                               err = cc.bw.Flush()
+                       }
+                       cc.wmu.Unlock()
+               }
+               if err != nil {
+                       return err
+               }
+       }
+
+       cc.wmu.Lock()
+       if !sentEnd {
+               var trls []byte
+               if hasTrailers {
+                       cc.mu.Lock()
+                       trls = cc.encodeTrailers(req)
+                       cc.mu.Unlock()
+               }
+
+               if len(trls) > 0 {
+                       err = cc.writeHeaders(cs.ID, true, trls)
+               } else {
+                       err = cc.fr.WriteData(cs.ID, true, nil)
+               }
+       }
+       if ferr := cc.bw.Flush(); ferr != nil && err == nil {
+               err = ferr
+       }
+       cc.wmu.Unlock()
+
+       return err
+}
+
+// awaitFlowControl waits for [1, min(maxBytes, cc.cs.maxFrameSize)] flow
+// control tokens from the server.
+// It returns either the non-zero number of tokens taken or an error
+// if the stream is dead.
+func (cs *http2clientStream) awaitFlowControl(maxBytes int) (taken int32, err error) {
+       cc := cs.cc
+       cc.mu.Lock()
+       defer cc.mu.Unlock()
+       for {
+               if cc.closed {
+                       return 0, http2errClientConnClosed
+               }
+               if cs.stopReqBody != nil {
+                       return 0, cs.stopReqBody
+               }
+               if err := cs.checkReset(); err != nil {
+                       return 0, err
+               }
+               if a := cs.flow.available(); a > 0 {
+                       take := a
+                       if int(take) > maxBytes {
+
+                               take = int32(maxBytes)
+                       }
+                       if take > int32(cc.maxFrameSize) {
+                               take = int32(cc.maxFrameSize)
+                       }
+                       cs.flow.take(take)
+                       return take, nil
+               }
+               cc.cond.Wait()
+       }
+}
+
+type http2badStringError struct {
+       what string
+       str  string
+}
+
+func (e *http2badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) }
+
+// requires cc.mu be held.
+func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trailers string, contentLength int64) []byte {
+       cc.hbuf.Reset()
+
+       host := req.Host
+       if host == "" {
+               host = req.URL.Host
+       }
+
+       cc.writeHeader(":authority", host)
+       cc.writeHeader(":method", req.Method)
+       if req.Method != "CONNECT" {
+               cc.writeHeader(":path", req.URL.RequestURI())
+               cc.writeHeader(":scheme", "https")
+       }
+       if trailers != "" {
+               cc.writeHeader("trailer", trailers)
+       }
+
+       var didUA bool
+       for k, vv := range req.Header {
+               lowKey := strings.ToLower(k)
+               if lowKey == "host" || lowKey == "content-length" {
+                       continue
+               }
+               if lowKey == "user-agent" {
+
+                       didUA = true
+                       if len(vv) < 1 {
+                               continue
+                       }
+                       vv = vv[:1]
+                       if vv[0] == "" {
+                               continue
+                       }
+               }
+               for _, v := range vv {
+                       cc.writeHeader(lowKey, v)
+               }
+       }
+       if http2shouldSendReqContentLength(req.Method, contentLength) {
+               cc.writeHeader("content-length", strconv.FormatInt(contentLength, 10))
+       }
+       if addGzipHeader {
+               cc.writeHeader("accept-encoding", "gzip")
+       }
+       if !didUA {
+               cc.writeHeader("user-agent", http2defaultUserAgent)
+       }
+       return cc.hbuf.Bytes()
+}
+
+// shouldSendReqContentLength reports whether the http2.Transport should send
+// a "content-length" request header. This logic is basically a copy of the net/http
+// transferWriter.shouldSendContentLength.
+// The contentLength is the corrected contentLength (so 0 means actually 0, not unknown).
+// -1 means unknown.
+func http2shouldSendReqContentLength(method string, contentLength int64) bool {
+       if contentLength > 0 {
+               return true
+       }
+       if contentLength < 0 {
+               return false
+       }
+
+       switch method {
+       case "POST", "PUT", "PATCH":
+               return true
+       default:
+               return false
+       }
+}
+
+// requires cc.mu be held.
+func (cc *http2ClientConn) encodeTrailers(req *Request) []byte {
+       cc.hbuf.Reset()
+       for k, vv := range req.Trailer {
+
+               lowKey := strings.ToLower(k)
+               for _, v := range vv {
+                       cc.writeHeader(lowKey, v)
+               }
+       }
+       return cc.hbuf.Bytes()
+}
+
+func (cc *http2ClientConn) writeHeader(name, value string) {
+       if http2VerboseLogs {
+               log.Printf("http2: Transport encoding header %q = %q", name, value)
+       }
+       cc.henc.WriteField(hpack.HeaderField{Name: name, Value: value})
+}
+
+type http2resAndError struct {
+       res *Response
+       err error
+}
+
+// requires cc.mu be held.
+func (cc *http2ClientConn) newStream() *http2clientStream {
+       cs := &http2clientStream{
+               cc:        cc,
+               ID:        cc.nextStreamID,
+               resc:      make(chan http2resAndError, 1),
+               peerReset: make(chan struct{}),
+               done:      make(chan struct{}),
+       }
+       cs.flow.add(int32(cc.initialWindowSize))
+       cs.flow.setConnFlow(&cc.flow)
+       cs.inflow.add(http2transportDefaultStreamFlow)
+       cs.inflow.setConnFlow(&cc.inflow)
+       cc.nextStreamID += 2
+       cc.streams[cs.ID] = cs
+       return cs
+}
+
+func (cc *http2ClientConn) forgetStreamID(id uint32) {
+       cc.streamByID(id, true)
+}
+
+func (cc *http2ClientConn) streamByID(id uint32, andRemove bool) *http2clientStream {
+       cc.mu.Lock()
+       defer cc.mu.Unlock()
+       cs := cc.streams[id]
+       if andRemove && cs != nil && !cc.closed {
+               delete(cc.streams, id)
+               close(cs.done)
+       }
+       return cs
+}
+
+// clientConnReadLoop is the state owned by the clientConn's frame-reading readLoop.
+type http2clientConnReadLoop struct {
+       cc        *http2ClientConn
+       activeRes map[uint32]*http2clientStream // keyed by streamID
+
+       hdec *hpack.Decoder
+
+       // Fields reset on each HEADERS:
+       nextRes              *Response
+       sawRegHeader         bool  // saw non-pseudo header
+       reqMalformed         error // non-nil once known to be malformed
+       lastHeaderEndsStream bool
+       headerListSize       int64 // actually uint32, but easier math this way
+}
+
+// readLoop runs in its own goroutine and reads and dispatches frames.
+func (cc *http2ClientConn) readLoop() {
+       rl := &http2clientConnReadLoop{
+               cc:        cc,
+               activeRes: make(map[uint32]*http2clientStream),
+       }
+       rl.hdec = hpack.NewDecoder(http2initialHeaderTableSize, rl.onNewHeaderField)
+
+       defer rl.cleanup()
+       cc.readerErr = rl.run()
+       if ce, ok := cc.readerErr.(http2ConnectionError); ok {
+               cc.wmu.Lock()
+               cc.fr.WriteGoAway(0, http2ErrCode(ce), nil)
+               cc.wmu.Unlock()
+       }
+}
+
+func (rl *http2clientConnReadLoop) cleanup() {
+       cc := rl.cc
+       defer cc.tconn.Close()
+       defer cc.t.connPool().MarkDead(cc)
+       defer close(cc.readerDone)
+
+       err := cc.readerErr
+       if err == io.EOF {
+               err = io.ErrUnexpectedEOF
+       }
+       cc.mu.Lock()
+       for _, cs := range rl.activeRes {
+               cs.bufPipe.CloseWithError(err)
+       }
+       for _, cs := range cc.streams {
+               select {
+               case cs.resc <- http2resAndError{err: err}:
+               default:
+               }
+               close(cs.done)
+       }
+       cc.closed = true
+       cc.cond.Broadcast()
+       cc.mu.Unlock()
+}
+
+func (rl *http2clientConnReadLoop) run() error {
+       cc := rl.cc
+       closeWhenIdle := cc.t.disableKeepAlives()
+       gotReply := false
+       for {
+               f, err := cc.fr.ReadFrame()
+               if err != nil {
+                       cc.vlogf("Transport readFrame error: (%T) %v", err, err)
+               }
+               if se, ok := err.(http2StreamError); ok {
+
+                       return se
+               } else if err != nil {
+                       return err
+               }
+               if http2VerboseLogs {
+                       cc.vlogf("http2: Transport received %s", http2summarizeFrame(f))
+               }
+               maybeIdle := false
+
+               switch f := f.(type) {
+               case *http2HeadersFrame:
+                       err = rl.processHeaders(f)
+                       maybeIdle = true
+                       gotReply = true
+               case *http2ContinuationFrame:
+                       err = rl.processContinuation(f)
+                       maybeIdle = true
+               case *http2DataFrame:
+                       err = rl.processData(f)
+                       maybeIdle = true
+               case *http2GoAwayFrame:
+                       err = rl.processGoAway(f)
+                       maybeIdle = true
+               case *http2RSTStreamFrame:
+                       err = rl.processResetStream(f)
+                       maybeIdle = true
+               case *http2SettingsFrame:
+                       err = rl.processSettings(f)
+               case *http2PushPromiseFrame:
+                       err = rl.processPushPromise(f)
+               case *http2WindowUpdateFrame:
+                       err = rl.processWindowUpdate(f)
+               case *http2PingFrame:
+                       err = rl.processPing(f)
+               default:
+                       cc.logf("Transport: unhandled response frame type %T", f)
+               }
+               if err != nil {
+                       return err
+               }
+               if closeWhenIdle && gotReply && maybeIdle && len(rl.activeRes) == 0 {
+                       cc.closeIfIdle()
+               }
+       }
+}
+
+func (rl *http2clientConnReadLoop) processHeaders(f *http2HeadersFrame) error {
+       rl.sawRegHeader = false
+       rl.reqMalformed = nil
+       rl.lastHeaderEndsStream = f.StreamEnded()
+       rl.headerListSize = 0
+       rl.nextRes = &Response{
+               Proto:      "HTTP/2.0",
+               ProtoMajor: 2,
+               Header:     make(Header),
+       }
+       rl.hdec.SetEmitEnabled(true)
+       return rl.processHeaderBlockFragment(f.HeaderBlockFragment(), f.StreamID, f.HeadersEnded())
+}
+
+func (rl *http2clientConnReadLoop) processContinuation(f *http2ContinuationFrame) error {
+       return rl.processHeaderBlockFragment(f.HeaderBlockFragment(), f.StreamID, f.HeadersEnded())
+}
+
+func (rl *http2clientConnReadLoop) processHeaderBlockFragment(frag []byte, streamID uint32, finalFrag bool) error {
+       cc := rl.cc
+       streamEnded := rl.lastHeaderEndsStream
+       cs := cc.streamByID(streamID, streamEnded && finalFrag)
+       if cs == nil {
+
+               return nil
+       }
+       if cs.pastHeaders {
+               rl.hdec.SetEmitFunc(func(f hpack.HeaderField) { rl.onNewTrailerField(cs, f) })
+       } else {
+               rl.hdec.SetEmitFunc(rl.onNewHeaderField)
+       }
+       _, err := rl.hdec.Write(frag)
+       if err != nil {
+               return http2ConnectionError(http2ErrCodeCompression)
+       }
+       if finalFrag {
+               if err := rl.hdec.Close(); err != nil {
+                       return http2ConnectionError(http2ErrCodeCompression)
+               }
+       }
+
+       if !finalFrag {
+               return nil
+       }
+
+       if !cs.pastHeaders {
+               cs.pastHeaders = true
+       } else {
+
+               if cs.pastTrailers {
+
+                       return http2ConnectionError(http2ErrCodeProtocol)
+               }
+               cs.pastTrailers = true
+               if !streamEnded {
+
+                       return http2ConnectionError(http2ErrCodeProtocol)
+               }
+               rl.endStream(cs)
+               return nil
+       }
+
+       if rl.reqMalformed != nil {
+               cs.resc <- http2resAndError{err: rl.reqMalformed}
+               rl.cc.writeStreamReset(cs.ID, http2ErrCodeProtocol, rl.reqMalformed)
+               return nil
+       }
+
+       res := rl.nextRes
+
+       if res.StatusCode == 100 {
+
+               cs.pastHeaders = false
+               return nil
+       }
+
+       if !streamEnded || cs.req.Method == "HEAD" {
+               res.ContentLength = -1
+               if clens := res.Header["Content-Length"]; len(clens) == 1 {
+                       if clen64, err := strconv.ParseInt(clens[0], 10, 64); err == nil {
+                               res.ContentLength = clen64
+                       } else {
+
+                       }
+               } else if len(clens) > 1 {
+
+               }
+       }
+
+       if streamEnded {
+               res.Body = http2noBody
+       } else {
+               buf := new(bytes.Buffer)
+               cs.bufPipe = http2pipe{b: buf}
+               cs.bytesRemain = res.ContentLength
+               res.Body = http2transportResponseBody{cs}
+               go cs.awaitRequestCancel(http2requestCancel(cs.req))
+
+               if cs.requestedGzip && res.Header.Get("Content-Encoding") == "gzip" {
+                       res.Header.Del("Content-Encoding")
+                       res.Header.Del("Content-Length")
+                       res.ContentLength = -1
+                       res.Body = &http2gzipReader{body: res.Body}
+               }
+       }
+
+       cs.resTrailer = &res.Trailer
+       rl.activeRes[cs.ID] = cs
+       cs.resc <- http2resAndError{res: res}
+       rl.nextRes = nil
+       return nil
+}
+
+// transportResponseBody is the concrete type of Transport.RoundTrip's
+// Response.Body. It is an io.ReadCloser. On Read, it reads from cs.body.
+// On Close it sends RST_STREAM if EOF wasn't already seen.
+type http2transportResponseBody struct {
+       cs *http2clientStream
+}
+
+func (b http2transportResponseBody) Read(p []byte) (n int, err error) {
+       cs := b.cs
+       cc := cs.cc
+
+       if cs.readErr != nil {
+               return 0, cs.readErr
+       }
+       n, err = b.cs.bufPipe.Read(p)
+       if cs.bytesRemain != -1 {
+               if int64(n) > cs.bytesRemain {
+                       n = int(cs.bytesRemain)
+                       if err == nil {
+                               err = errors.New("net/http: server replied with more than declared Content-Length; truncated")
+                               cc.writeStreamReset(cs.ID, http2ErrCodeProtocol, err)
+                       }
+                       cs.readErr = err
+                       return int(cs.bytesRemain), err
+               }
+               cs.bytesRemain -= int64(n)
+               if err == io.EOF && cs.bytesRemain > 0 {
+                       err = io.ErrUnexpectedEOF
+                       cs.readErr = err
+                       return n, err
+               }
+       }
+       if n == 0 {
+
+               return
+       }
+
+       cc.mu.Lock()
+       defer cc.mu.Unlock()
+
+       var connAdd, streamAdd int32
+
+       if v := cc.inflow.available(); v < http2transportDefaultConnFlow/2 {
+               connAdd = http2transportDefaultConnFlow - v
+               cc.inflow.add(connAdd)
+       }
+       if err == nil {
+               if v := cs.inflow.available(); v < http2transportDefaultStreamFlow-http2transportDefaultStreamMinRefresh {
+                       streamAdd = http2transportDefaultStreamFlow - v
+                       cs.inflow.add(streamAdd)
+               }
+       }
+       if connAdd != 0 || streamAdd != 0 {
+               cc.wmu.Lock()
+               defer cc.wmu.Unlock()
+               if connAdd != 0 {
+                       cc.fr.WriteWindowUpdate(0, http2mustUint31(connAdd))
+               }
+               if streamAdd != 0 {
+                       cc.fr.WriteWindowUpdate(cs.ID, http2mustUint31(streamAdd))
+               }
+               cc.bw.Flush()
+       }
+       return
+}
+
+var http2errClosedResponseBody = errors.New("http2: response body closed")
+
+func (b http2transportResponseBody) Close() error {
+       cs := b.cs
+       if cs.bufPipe.Err() != io.EOF {
+
+               cs.cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
+       }
+       cs.bufPipe.BreakWithError(http2errClosedResponseBody)
+       return nil
+}
+
+func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error {
+       cc := rl.cc
+       cs := cc.streamByID(f.StreamID, f.StreamEnded())
+       if cs == nil {
+               cc.mu.Lock()
+               neverSent := cc.nextStreamID
+               cc.mu.Unlock()
+               if f.StreamID >= neverSent {
+
+                       cc.logf("http2: Transport received unsolicited DATA frame; closing connection")
+                       return http2ConnectionError(http2ErrCodeProtocol)
+               }
+
+               return nil
+       }
+       if data := f.Data(); len(data) > 0 {
+               if cs.bufPipe.b == nil {
+
+                       cc.logf("http2: Transport received DATA frame for closed stream; closing connection")
+                       return http2ConnectionError(http2ErrCodeProtocol)
+               }
+
+               cc.mu.Lock()
+               if cs.inflow.available() >= int32(len(data)) {
+                       cs.inflow.take(int32(len(data)))
+               } else {
+                       cc.mu.Unlock()
+                       return http2ConnectionError(http2ErrCodeFlowControl)
+               }
+               cc.mu.Unlock()
+
+               if _, err := cs.bufPipe.Write(data); err != nil {
+                       return err
+               }
+       }
+
+       if f.StreamEnded() {
+               rl.endStream(cs)
+       }
+       return nil
+}
+
+var http2errInvalidTrailers = errors.New("http2: invalid trailers")
+
+func (rl *http2clientConnReadLoop) endStream(cs *http2clientStream) {
+
+       err := io.EOF
+       code := cs.copyTrailers
+       if rl.reqMalformed != nil {
+               err = rl.reqMalformed
+               code = nil
+       }
+       cs.bufPipe.closeWithErrorAndCode(err, code)
+       delete(rl.activeRes, cs.ID)
+}
+
+func (cs *http2clientStream) copyTrailers() {
+       for k, vv := range cs.trailer {
+               t := cs.resTrailer
+               if *t == nil {
+                       *t = make(Header)
+               }
+               (*t)[k] = vv
+       }
+}
+
+func (rl *http2clientConnReadLoop) processGoAway(f *http2GoAwayFrame) error {
+       cc := rl.cc
+       cc.t.connPool().MarkDead(cc)
+       if f.ErrCode != 0 {
+
+               cc.vlogf("transport got GOAWAY with error code = %v", f.ErrCode)
+       }
+       cc.setGoAway(f)
+       return nil
+}
+
+func (rl *http2clientConnReadLoop) processSettings(f *http2SettingsFrame) error {
+       cc := rl.cc
+       cc.mu.Lock()
+       defer cc.mu.Unlock()
+       return f.ForeachSetting(func(s http2Setting) error {
+               switch s.ID {
+               case http2SettingMaxFrameSize:
+                       cc.maxFrameSize = s.Val
+               case http2SettingMaxConcurrentStreams:
+                       cc.maxConcurrentStreams = s.Val
+               case http2SettingInitialWindowSize:
+
+                       cc.initialWindowSize = s.Val
+               default:
+
+                       cc.vlogf("Unhandled Setting: %v", s)
+               }
+               return nil
+       })
+}
+
+func (rl *http2clientConnReadLoop) processWindowUpdate(f *http2WindowUpdateFrame) error {
+       cc := rl.cc
+       cs := cc.streamByID(f.StreamID, false)
+       if f.StreamID != 0 && cs == nil {
+               return nil
+       }
+
+       cc.mu.Lock()
+       defer cc.mu.Unlock()
+
+       fl := &cc.flow
+       if cs != nil {
+               fl = &cs.flow
+       }
+       if !fl.add(int32(f.Increment)) {
+               return http2ConnectionError(http2ErrCodeFlowControl)
+       }
+       cc.cond.Broadcast()
+       return nil
+}
+
+func (rl *http2clientConnReadLoop) processResetStream(f *http2RSTStreamFrame) error {
+       cs := rl.cc.streamByID(f.StreamID, true)
+       if cs == nil {
+
+               return nil
+       }
+       select {
+       case <-cs.peerReset:
+
+       default:
+               err := http2StreamError{cs.ID, f.ErrCode}
+               cs.resetErr = err
+               close(cs.peerReset)
+               cs.bufPipe.CloseWithError(err)
+               cs.cc.cond.Broadcast()
+       }
+       delete(rl.activeRes, cs.ID)
+       return nil
+}
+
+func (rl *http2clientConnReadLoop) processPing(f *http2PingFrame) error {
+       if f.IsAck() {
+
+               return nil
+       }
+       cc := rl.cc
+       cc.wmu.Lock()
+       defer cc.wmu.Unlock()
+       if err := cc.fr.WritePing(true, f.Data); err != nil {
+               return err
+       }
+       return cc.bw.Flush()
+}
+
+func (rl *http2clientConnReadLoop) processPushPromise(f *http2PushPromiseFrame) error {
+
+       return http2ConnectionError(http2ErrCodeProtocol)
+}
+
+func (cc *http2ClientConn) writeStreamReset(streamID uint32, code http2ErrCode, err error) {
+
+       cc.wmu.Lock()
+       cc.fr.WriteRSTStream(streamID, code)
+       cc.bw.Flush()
+       cc.wmu.Unlock()
+}
+
+var (
+       http2errResponseHeaderListSize = errors.New("http2: response header list larger than advertised limit")
+       http2errPseudoTrailers         = errors.New("http2: invalid pseudo header in trailers")
+)
+
+func (rl *http2clientConnReadLoop) checkHeaderField(f hpack.HeaderField) bool {
+       if rl.reqMalformed != nil {
+               return false
+       }
+
+       const headerFieldOverhead = 32 // per spec
+       rl.headerListSize += int64(len(f.Name)) + int64(len(f.Value)) + headerFieldOverhead
+       if max := rl.cc.t.maxHeaderListSize(); max != 0 && rl.headerListSize > int64(max) {
+               rl.hdec.SetEmitEnabled(false)
+               rl.reqMalformed = http2errResponseHeaderListSize
+               return false
+       }
+
+       if !http2validHeaderFieldValue(f.Value) {
+               rl.reqMalformed = http2errInvalidHeaderFieldValue
+               return false
+       }
+
+       isPseudo := strings.HasPrefix(f.Name, ":")
+       if isPseudo {
+               if rl.sawRegHeader {
+                       rl.reqMalformed = errors.New("http2: invalid pseudo header after regular header")
+                       return false
+               }
+       } else {
+               if !http2validHeaderFieldName(f.Name) {
+                       rl.reqMalformed = http2errInvalidHeaderFieldName
+                       return false
+               }
+               rl.sawRegHeader = true
+       }
+
+       return true
+}
+
+// onNewHeaderField runs on the readLoop goroutine whenever a new
+// hpack header field is decoded.
+func (rl *http2clientConnReadLoop) onNewHeaderField(f hpack.HeaderField) {
+       cc := rl.cc
+       if http2VerboseLogs {
+               cc.logf("http2: Transport decoded %v", f)
+       }
+
+       if !rl.checkHeaderField(f) {
+               return
+       }
+
+       isPseudo := strings.HasPrefix(f.Name, ":")
+       if isPseudo {
+               switch f.Name {
+               case ":status":
+                       code, err := strconv.Atoi(f.Value)
+                       if err != nil {
+                               rl.reqMalformed = errors.New("http2: invalid :status")
+                               return
+                       }
+                       rl.nextRes.Status = f.Value + " " + StatusText(code)
+                       rl.nextRes.StatusCode = code
+               default:
+
+                       rl.reqMalformed = fmt.Errorf("http2: unknown response pseudo header %q", f.Name)
+               }
+               return
+       }
+
+       key := CanonicalHeaderKey(f.Name)
+       if key == "Trailer" {
+               t := rl.nextRes.Trailer
+               if t == nil {
+                       t = make(Header)
+                       rl.nextRes.Trailer = t
+               }
+               http2foreachHeaderElement(f.Value, func(v string) {
+                       t[CanonicalHeaderKey(v)] = nil
+               })
+       } else {
+               rl.nextRes.Header.Add(key, f.Value)
+       }
+}
+
+func (rl *http2clientConnReadLoop) onNewTrailerField(cs *http2clientStream, f hpack.HeaderField) {
+       if http2VerboseLogs {
+               rl.cc.logf("http2: Transport decoded trailer %v", f)
+       }
+       if !rl.checkHeaderField(f) {
+               return
+       }
+       if strings.HasPrefix(f.Name, ":") {
+
+               rl.reqMalformed = http2errPseudoTrailers
+               return
+       }
+
+       key := CanonicalHeaderKey(f.Name)
+
+       // The spec says one must predeclare their trailers but in practice
+       // popular users (which is to say the only user we found) do not so we
+       // violate the spec and accept all of them.
+       const acceptAllTrailers = true
+       if _, ok := (*cs.resTrailer)[key]; ok || acceptAllTrailers {
+               if cs.trailer == nil {
+                       cs.trailer = make(Header)
+               }
+               cs.trailer[key] = append(cs.trailer[key], f.Value)
+       }
+}
+
+func (cc *http2ClientConn) logf(format string, args ...interface{}) {
+       cc.t.logf(format, args...)
+}
+
+func (cc *http2ClientConn) vlogf(format string, args ...interface{}) {
+       cc.t.vlogf(format, args...)
+}
+
+func (t *http2Transport) vlogf(format string, args ...interface{}) {
+       if http2VerboseLogs {
+               t.logf(format, args...)
+       }
+}
+
+func (t *http2Transport) logf(format string, args ...interface{}) {
+       log.Printf(format, args...)
+}
+
+var http2noBody io.ReadCloser = ioutil.NopCloser(bytes.NewReader(nil))
+
+func http2strSliceContains(ss []string, s string) bool {
+       for _, v := range ss {
+               if v == s {
+                       return true
+               }
+       }
+       return false
+}
+
+type http2erringRoundTripper struct{ err error }
+
+func (rt http2erringRoundTripper) RoundTrip(*Request) (*Response, error) { return nil, rt.err }
+
+// gzipReader wraps a response body so it can lazily
+// call gzip.NewReader on the first call to Read
+type http2gzipReader struct {
+       body io.ReadCloser // underlying Response.Body
+       zr   io.Reader     // lazily-initialized gzip reader
+}
+
+func (gz *http2gzipReader) 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 *http2gzipReader) Close() error {
+       return gz.body.Close()
+}
+
+type http2errorReader struct{ err error }
+
+func (r http2errorReader) Read(p []byte) (int, error) { return 0, r.err }
+
+// writeFramer is implemented by any type that is used to write frames.
+type http2writeFramer interface {
+       writeFrame(http2writeContext) error
+}
+
+// writeContext is the interface needed by the various frame writer
+// types below. All the writeFrame methods below are scheduled via the
+// frame writing scheduler (see writeScheduler in writesched.go).
+//
+// This interface is implemented by *serverConn.
+//
+// TODO: decide whether to a) use this in the client code (which didn't
+// end up using this yet, because it has a simpler design, not
+// currently implementing priorities), or b) delete this and
+// make the server code a bit more concrete.
+type http2writeContext interface {
+       Framer() *http2Framer
+       Flush() error
+       CloseConn() error
+       // HeaderEncoder returns an HPACK encoder that writes to the
+       // returned buffer.
+       HeaderEncoder() (*hpack.Encoder, *bytes.Buffer)
+}
+
+// endsStream reports whether the given frame writer w will locally
+// close the stream.
+func http2endsStream(w http2writeFramer) bool {
+       switch v := w.(type) {
+       case *http2writeData:
+               return v.endStream
+       case *http2writeResHeaders:
+               return v.endStream
+       case nil:
+
+               panic("endsStream called on nil writeFramer")
+       }
+       return false
+}
+
+type http2flushFrameWriter struct{}
+
+func (http2flushFrameWriter) writeFrame(ctx http2writeContext) error {
+       return ctx.Flush()
+}
+
+type http2writeSettings []http2Setting
+
+func (s http2writeSettings) writeFrame(ctx http2writeContext) error {
+       return ctx.Framer().WriteSettings([]http2Setting(s)...)
+}
+
+type http2writeGoAway struct {
+       maxStreamID uint32
+       code        http2ErrCode
+}
+
+func (p *http2writeGoAway) writeFrame(ctx http2writeContext) error {
+       err := ctx.Framer().WriteGoAway(p.maxStreamID, p.code, nil)
+       if p.code != 0 {
+               ctx.Flush()
+               time.Sleep(50 * time.Millisecond)
+               ctx.CloseConn()
+       }
+       return err
+}
+
+type http2writeData struct {
+       streamID  uint32
+       p         []byte
+       endStream bool
+}
+
+func (w *http2writeData) String() string {
+       return fmt.Sprintf("writeData(stream=%d, p=%d, endStream=%v)", w.streamID, len(w.p), w.endStream)
+}
+
+func (w *http2writeData) writeFrame(ctx http2writeContext) error {
+       return ctx.Framer().WriteData(w.streamID, w.endStream, w.p)
+}
+
+// handlerPanicRST is the message sent from handler goroutines when
+// the handler panics.
+type http2handlerPanicRST struct {
+       StreamID uint32
+}
+
+func (hp http2handlerPanicRST) writeFrame(ctx http2writeContext) error {
+       return ctx.Framer().WriteRSTStream(hp.StreamID, http2ErrCodeInternal)
+}
+
+func (se http2StreamError) writeFrame(ctx http2writeContext) error {
+       return ctx.Framer().WriteRSTStream(se.StreamID, se.Code)
+}
+
+type http2writePingAck struct{ pf *http2PingFrame }
+
+func (w http2writePingAck) writeFrame(ctx http2writeContext) error {
+       return ctx.Framer().WritePing(true, w.pf.Data)
+}
+
+type http2writeSettingsAck struct{}
+
+func (http2writeSettingsAck) writeFrame(ctx http2writeContext) error {
+       return ctx.Framer().WriteSettingsAck()
+}
+
+// writeResHeaders is a request to write a HEADERS and 0+ CONTINUATION frames
+// for HTTP response headers or trailers from a server handler.
+type http2writeResHeaders struct {
+       streamID    uint32
+       httpResCode int      // 0 means no ":status" line
+       h           Header   // may be nil
+       trailers    []string // if non-nil, which keys of h to write. nil means all.
+       endStream   bool
+
+       date          string
+       contentType   string
+       contentLength string
+}
+
+func http2encKV(enc *hpack.Encoder, k, v string) {
+       if http2VerboseLogs {
+               log.Printf("http2: server encoding header %q = %q", k, v)
+       }
+       enc.WriteField(hpack.HeaderField{Name: k, Value: v})
+}
+
+func (w *http2writeResHeaders) writeFrame(ctx http2writeContext) error {
+       enc, buf := ctx.HeaderEncoder()
+       buf.Reset()
+
+       if w.httpResCode != 0 {
+               http2encKV(enc, ":status", http2httpCodeString(w.httpResCode))
+       }
+
+       http2encodeHeaders(enc, w.h, w.trailers)
+
+       if w.contentType != "" {
+               http2encKV(enc, "content-type", w.contentType)
+       }
+       if w.contentLength != "" {
+               http2encKV(enc, "content-length", w.contentLength)
+       }
+       if w.date != "" {
+               http2encKV(enc, "date", w.date)
+       }
+
+       headerBlock := buf.Bytes()
+       if len(headerBlock) == 0 && w.trailers == nil {
+               panic("unexpected empty hpack")
+       }
+
+       // For now we're lazy and just pick the minimum MAX_FRAME_SIZE
+       // that all peers must support (16KB). Later we could care
+       // more and send larger frames if the peer advertised it, but
+       // there's little point. Most headers are small anyway (so we
+       // generally won't have CONTINUATION frames), and extra frames
+       // only waste 9 bytes anyway.
+       const maxFrameSize = 16384
+
+       first := true
+       for len(headerBlock) > 0 {
+               frag := headerBlock
+               if len(frag) > maxFrameSize {
+                       frag = frag[:maxFrameSize]
+               }
+               headerBlock = headerBlock[len(frag):]
+               endHeaders := len(headerBlock) == 0
+               var err error
+               if first {
+                       first = false
+                       err = ctx.Framer().WriteHeaders(http2HeadersFrameParam{
+                               StreamID:      w.streamID,
+                               BlockFragment: frag,
+                               EndStream:     w.endStream,
+                               EndHeaders:    endHeaders,
+                       })
+               } else {
+                       err = ctx.Framer().WriteContinuation(w.streamID, endHeaders, frag)
+               }
+               if err != nil {
+                       return err
+               }
+       }
+       return nil
+}
+
+type http2write100ContinueHeadersFrame struct {
+       streamID uint32
+}
+
+func (w http2write100ContinueHeadersFrame) writeFrame(ctx http2writeContext) error {
+       enc, buf := ctx.HeaderEncoder()
+       buf.Reset()
+       http2encKV(enc, ":status", "100")
+       return ctx.Framer().WriteHeaders(http2HeadersFrameParam{
+               StreamID:      w.streamID,
+               BlockFragment: buf.Bytes(),
+               EndStream:     false,
+               EndHeaders:    true,
+       })
+}
+
+type http2writeWindowUpdate struct {
+       streamID uint32 // or 0 for conn-level
+       n        uint32
+}
+
+func (wu http2writeWindowUpdate) writeFrame(ctx http2writeContext) error {
+       return ctx.Framer().WriteWindowUpdate(wu.streamID, wu.n)
+}
+
+func http2encodeHeaders(enc *hpack.Encoder, h Header, keys []string) {
+
+       if keys == nil {
+               keys = make([]string, 0, len(h))
+               for k := range h {
+                       keys = append(keys, k)
+               }
+               sort.Strings(keys)
+       }
+       for _, k := range keys {
+               vv := h[k]
+               k = http2lowerHeader(k)
+               isTE := k == "transfer-encoding"
+               for _, v := range vv {
+
+                       if isTE && v != "trailers" {
+                               continue
+                       }
+                       http2encKV(enc, k, v)
+               }
+       }
+}
+
+// frameWriteMsg is a request to write a frame.
+type http2frameWriteMsg struct {
+       // write is the interface value that does the writing, once the
+       // writeScheduler (below) has decided to select this frame
+       // to write. The write functions are all defined in write.go.
+       write http2writeFramer
+
+       stream *http2stream // used for prioritization. nil for non-stream frames.
+
+       // done, if non-nil, must be a buffered channel with space for
+       // 1 message and is sent the return value from write (or an
+       // earlier error) when the frame has been written.
+       done chan error
+}
+
+// for debugging only:
+func (wm http2frameWriteMsg) String() string {
+       var streamID uint32
+       if wm.stream != nil {
+               streamID = wm.stream.id
+       }
+       var des string
+       if s, ok := wm.write.(fmt.Stringer); ok {
+               des = s.String()
+       } else {
+               des = fmt.Sprintf("%T", wm.write)
+       }
+       return fmt.Sprintf("[frameWriteMsg stream=%d, ch=%v, type: %v]", streamID, wm.done != nil, des)
+}
+
+// writeScheduler tracks pending frames to write, priorities, and decides
+// the next one to use. It is not thread-safe.
+type http2writeScheduler struct {
+       // zero are frames not associated with a specific stream.
+       // They're sent before any stream-specific freams.
+       zero http2writeQueue
+
+       // maxFrameSize is the maximum size of a DATA frame
+       // we'll write. Must be non-zero and between 16K-16M.
+       maxFrameSize uint32
+
+       // sq contains the stream-specific queues, keyed by stream ID.
+       // when a stream is idle, it's deleted from the map.
+       sq map[uint32]*http2writeQueue
+
+       // canSend is a slice of memory that's reused between frame
+       // scheduling decisions to hold the list of writeQueues (from sq)
+       // which have enough flow control data to send. After canSend is
+       // built, the best is selected.
+       canSend []*http2writeQueue
+
+       // pool of empty queues for reuse.
+       queuePool []*http2writeQueue
+}
+
+func (ws *http2writeScheduler) putEmptyQueue(q *http2writeQueue) {
+       if len(q.s) != 0 {
+               panic("queue must be empty")
+       }
+       ws.queuePool = append(ws.queuePool, q)
+}
+
+func (ws *http2writeScheduler) getEmptyQueue() *http2writeQueue {
+       ln := len(ws.queuePool)
+       if ln == 0 {
+               return new(http2writeQueue)
+       }
+       q := ws.queuePool[ln-1]
+       ws.queuePool = ws.queuePool[:ln-1]
+       return q
+}
+
+func (ws *http2writeScheduler) empty() bool { return ws.zero.empty() && len(ws.sq) == 0 }
+
+func (ws *http2writeScheduler) add(wm http2frameWriteMsg) {
+       st := wm.stream
+       if st == nil {
+               ws.zero.push(wm)
+       } else {
+               ws.streamQueue(st.id).push(wm)
+       }
+}
+
+func (ws *http2writeScheduler) streamQueue(streamID uint32) *http2writeQueue {
+       if q, ok := ws.sq[streamID]; ok {
+               return q
+       }
+       if ws.sq == nil {
+               ws.sq = make(map[uint32]*http2writeQueue)
+       }
+       q := ws.getEmptyQueue()
+       ws.sq[streamID] = q
+       return q
+}
+
+// take returns the most important frame to write and removes it from the scheduler.
+// It is illegal to call this if the scheduler is empty or if there are no connection-level
+// flow control bytes available.
+func (ws *http2writeScheduler) take() (wm http2frameWriteMsg, ok bool) {
+       if ws.maxFrameSize == 0 {
+               panic("internal error: ws.maxFrameSize not initialized or invalid")
+       }
+
+       if !ws.zero.empty() {
+               return ws.zero.shift(), true
+       }
+       if len(ws.sq) == 0 {
+               return
+       }
+
+       for id, q := range ws.sq {
+               if q.firstIsNoCost() {
+                       return ws.takeFrom(id, q)
+               }
+       }
+
+       if len(ws.canSend) != 0 {
+               panic("should be empty")
+       }
+       for _, q := range ws.sq {
+               if n := ws.streamWritableBytes(q); n > 0 {
+                       ws.canSend = append(ws.canSend, q)
+               }
+       }
+       if len(ws.canSend) == 0 {
+               return
+       }
+       defer ws.zeroCanSend()
+
+       q := ws.canSend[0]
+
+       return ws.takeFrom(q.streamID(), q)
+}
+
+// zeroCanSend is defered from take.
+func (ws *http2writeScheduler) zeroCanSend() {
+       for i := range ws.canSend {
+               ws.canSend[i] = nil
+       }
+       ws.canSend = ws.canSend[:0]
+}
+
+// streamWritableBytes returns the number of DATA bytes we could write
+// from the given queue's stream, if this stream/queue were
+// selected. It is an error to call this if q's head isn't a
+// *writeData.
+func (ws *http2writeScheduler) streamWritableBytes(q *http2writeQueue) int32 {
+       wm := q.head()
+       ret := wm.stream.flow.available()
+       if ret == 0 {
+               return 0
+       }
+       if int32(ws.maxFrameSize) < ret {
+               ret = int32(ws.maxFrameSize)
+       }
+       if ret == 0 {
+               panic("internal error: ws.maxFrameSize not initialized or invalid")
+       }
+       wd := wm.write.(*http2writeData)
+       if len(wd.p) < int(ret) {
+               ret = int32(len(wd.p))
+       }
+       return ret
+}
+
+func (ws *http2writeScheduler) takeFrom(id uint32, q *http2writeQueue) (wm http2frameWriteMsg, ok bool) {
+       wm = q.head()
+
+       if wd, ok := wm.write.(*http2writeData); ok && len(wd.p) > 0 {
+               allowed := wm.stream.flow.available()
+               if allowed == 0 {
+
+                       return http2frameWriteMsg{}, false
+               }
+               if int32(ws.maxFrameSize) < allowed {
+                       allowed = int32(ws.maxFrameSize)
+               }
+
+               if len(wd.p) > int(allowed) {
+                       wm.stream.flow.take(allowed)
+                       chunk := wd.p[:allowed]
+                       wd.p = wd.p[allowed:]
+
+                       return http2frameWriteMsg{
+                               stream: wm.stream,
+                               write: &http2writeData{
+                                       streamID: wd.streamID,
+                                       p:        chunk,
+
+                                       endStream: false,
+                               },
+
+                               done: nil,
+                       }, true
+               }
+               wm.stream.flow.take(int32(len(wd.p)))
+       }
+
+       q.shift()
+       if q.empty() {
+               ws.putEmptyQueue(q)
+               delete(ws.sq, id)
+       }
+       return wm, true
+}
+
+func (ws *http2writeScheduler) forgetStream(id uint32) {
+       q, ok := ws.sq[id]
+       if !ok {
+               return
+       }
+       delete(ws.sq, id)
+
+       for i := range q.s {
+               q.s[i] = http2frameWriteMsg{}
+       }
+       q.s = q.s[:0]
+       ws.putEmptyQueue(q)
+}
+
+type http2writeQueue struct {
+       s []http2frameWriteMsg
+}
+
+// streamID returns the stream ID for a non-empty stream-specific queue.
+func (q *http2writeQueue) streamID() uint32 { return q.s[0].stream.id }
+
+func (q *http2writeQueue) empty() bool { return len(q.s) == 0 }
+
+func (q *http2writeQueue) push(wm http2frameWriteMsg) {
+       q.s = append(q.s, wm)
+}
+
+// head returns the next item that would be removed by shift.
+func (q *http2writeQueue) head() http2frameWriteMsg {
+       if len(q.s) == 0 {
+               panic("invalid use of queue")
+       }
+       return q.s[0]
+}
+
+func (q *http2writeQueue) shift() http2frameWriteMsg {
+       if len(q.s) == 0 {
+               panic("invalid use of queue")
+       }
+       wm := q.s[0]
+
+       copy(q.s, q.s[1:])
+       q.s[len(q.s)-1] = http2frameWriteMsg{}
+       q.s = q.s[:len(q.s)-1]
+       return wm
+}
+
+func (q *http2writeQueue) firstIsNoCost() bool {
+       if df, ok := q.s[0].write.(*http2writeData); ok {
+               return len(df.p) == 0
+       }
+       return true
+}
index d847b131184d3eac715b67de5ffb1d6f5fcaf6c7..049f32f27dc35ee2ea7be28478efd8846efaac52 100644 (file)
@@ -211,3 +211,13 @@ func hasToken(v, token string) bool {
 func isTokenBoundary(b byte) bool {
        return b == ' ' || b == ',' || b == '\t'
 }
+
+func cloneHeader(h Header) Header {
+       h2 := make(Header, len(h))
+       for k, vv := range h {
+               vv2 := make([]string, len(vv))
+               copy(vv2, vv)
+               h2[k] = vv2
+       }
+       return h2
+}
index 5451f54234c9e6dfa8a5bbc6796495432d478085..7c51af1867a078b1af1c0739c9f50e1cab2547be 100644 (file)
@@ -44,23 +44,60 @@ func (rw *ResponseRecorder) Header() http.Header {
        return m
 }
 
+// writeHeader writes a header if it was not written yet and
+// detects Content-Type if needed.
+//
+// bytes or str are the beginning of the response body.
+// We pass both to avoid unnecessarily generate garbage
+// in rw.WriteString which was created for performance reasons.
+// Non-nil bytes win.
+func (rw *ResponseRecorder) writeHeader(b []byte, str string) {
+       if rw.wroteHeader {
+               return
+       }
+       if len(str) > 512 {
+               str = str[:512]
+       }
+
+       _, hasType := rw.HeaderMap["Content-Type"]
+       hasTE := rw.HeaderMap.Get("Transfer-Encoding") != ""
+       if !hasType && !hasTE {
+               if b == nil {
+                       b = []byte(str)
+               }
+               if rw.HeaderMap == nil {
+                       rw.HeaderMap = make(http.Header)
+               }
+               rw.HeaderMap.Set("Content-Type", http.DetectContentType(b))
+       }
+
+       rw.WriteHeader(200)
+}
+
 // Write always succeeds and writes to rw.Body, if not nil.
 func (rw *ResponseRecorder) Write(buf []byte) (int, error) {
-       if !rw.wroteHeader {
-               rw.WriteHeader(200)
-       }
+       rw.writeHeader(buf, "")
        if rw.Body != nil {
                rw.Body.Write(buf)
        }
        return len(buf), nil
 }
 
+// WriteString always succeeds and writes to rw.Body, if not nil.
+func (rw *ResponseRecorder) WriteString(str string) (int, error) {
+       rw.writeHeader(nil, str)
+       if rw.Body != nil {
+               rw.Body.WriteString(str)
+       }
+       return len(str), nil
+}
+
 // WriteHeader sets rw.Code.
 func (rw *ResponseRecorder) WriteHeader(code int) {
        if !rw.wroteHeader {
                rw.Code = code
+               rw.wroteHeader = true
        }
-       rw.wroteHeader = true
 }
 
 // Flush sets rw.Flushed to true.
index 2b563260c769aaa56079cedd249c375b95231394..c29b6d4cf91d307f786e681cf6e166a22e903cf0 100644 (file)
@@ -6,6 +6,7 @@ package httptest
 
 import (
        "fmt"
+       "io"
        "net/http"
        "testing"
 )
@@ -38,6 +39,14 @@ func TestRecorder(t *testing.T) {
                        return nil
                }
        }
+       hasHeader := func(key, want string) checkFunc {
+               return func(rec *ResponseRecorder) error {
+                       if got := rec.HeaderMap.Get(key); got != want {
+                               return fmt.Errorf("header %s = %q; want %q", key, got, want)
+                       }
+                       return nil
+               }
+       }
 
        tests := []struct {
                name   string
@@ -67,6 +76,18 @@ func TestRecorder(t *testing.T) {
                        },
                        check(hasStatus(200), hasContents("hi first"), hasFlush(false)),
                },
+               {
+                       "write string",
+                       func(w http.ResponseWriter, r *http.Request) {
+                               io.WriteString(w, "hi first")
+                       },
+                       check(
+                               hasStatus(200),
+                               hasContents("hi first"),
+                               hasFlush(false),
+                               hasHeader("Content-Type", "text/plain; charset=utf-8"),
+                       ),
+               },
                {
                        "flush",
                        func(w http.ResponseWriter, r *http.Request) {
@@ -75,6 +96,40 @@ func TestRecorder(t *testing.T) {
                        },
                        check(hasStatus(200), hasFlush(true)),
                },
+               {
+                       "Content-Type detection",
+                       func(w http.ResponseWriter, r *http.Request) {
+                               io.WriteString(w, "<html>")
+                       },
+                       check(hasHeader("Content-Type", "text/html; charset=utf-8")),
+               },
+               {
+                       "no Content-Type detection with Transfer-Encoding",
+                       func(w http.ResponseWriter, r *http.Request) {
+                               w.Header().Set("Transfer-Encoding", "some encoding")
+                               io.WriteString(w, "<html>")
+                       },
+                       check(hasHeader("Content-Type", "")), // no header
+               },
+               {
+                       "no Content-Type detection if set explicitly",
+                       func(w http.ResponseWriter, r *http.Request) {
+                               w.Header().Set("Content-Type", "some/type")
+                               io.WriteString(w, "<html>")
+                       },
+                       check(hasHeader("Content-Type", "some/type")),
+               },
+               {
+                       "Content-Type detection doesn't crash if HeaderMap is nil",
+                       func(w http.ResponseWriter, r *http.Request) {
+                               // Act as if the user wrote new(httptest.ResponseRecorder)
+                               // rather than using NewRecorder (which initializes
+                               // HeaderMap)
+                               w.(*ResponseRecorder).HeaderMap = nil
+                               io.WriteString(w, "<html>")
+                       },
+                       check(hasHeader("Content-Type", "text/html; charset=utf-8")),
+               },
        }
        r, _ := http.NewRequest("GET", "http://foo.com/", nil)
        for _, tt := range tests {
index 96eb0ef6d2f147b74e86e7c9b0a09ef7afec3d57..5c19c0ca3403aee1673d5b9d557afc39af01dd57 100644 (file)
@@ -7,13 +7,18 @@
 package httptest
 
 import (
+       "bytes"
        "crypto/tls"
        "flag"
        "fmt"
+       "log"
        "net"
        "net/http"
+       "net/http/internal"
        "os"
+       "runtime"
        "sync"
+       "time"
 )
 
 // A Server is an HTTP server listening on a system-chosen port on the
@@ -34,24 +39,10 @@ type Server struct {
        // wg counts the number of outstanding HTTP requests on this server.
        // Close blocks until all requests are finished.
        wg sync.WaitGroup
-}
-
-// historyListener keeps track of all connections that it's ever
-// accepted.
-type historyListener struct {
-       net.Listener
-       sync.Mutex // protects history
-       history    []net.Conn
-}
 
-func (hs *historyListener) Accept() (c net.Conn, err error) {
-       c, err = hs.Listener.Accept()
-       if err == nil {
-               hs.Lock()
-               hs.history = append(hs.history, c)
-               hs.Unlock()
-       }
-       return
+       mu     sync.Mutex // guards closed and conns
+       closed bool
+       conns  map[net.Conn]http.ConnState // except terminal states
 }
 
 func newLocalListener() net.Listener {
@@ -103,10 +94,9 @@ func (s *Server) Start() {
        if s.URL != "" {
                panic("Server already started")
        }
-       s.Listener = &historyListener{Listener: s.Listener}
        s.URL = "http://" + s.Listener.Addr().String()
-       s.wrapHandler()
-       go s.Config.Serve(s.Listener)
+       s.wrap()
+       s.goServe()
        if *serve != "" {
                fmt.Fprintln(os.Stderr, "httptest: serving on", s.URL)
                select {}
@@ -118,7 +108,7 @@ func (s *Server) StartTLS() {
        if s.URL != "" {
                panic("Server already started")
        }
-       cert, err := tls.X509KeyPair(localhostCert, localhostKey)
+       cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey)
        if err != nil {
                panic(fmt.Sprintf("httptest: NewTLSServer: %v", err))
        }
@@ -134,23 +124,10 @@ func (s *Server) StartTLS() {
        if len(s.TLS.Certificates) == 0 {
                s.TLS.Certificates = []tls.Certificate{cert}
        }
-       tlsListener := tls.NewListener(s.Listener, s.TLS)
-
-       s.Listener = &historyListener{Listener: tlsListener}
+       s.Listener = tls.NewListener(s.Listener, s.TLS)
        s.URL = "https://" + s.Listener.Addr().String()
-       s.wrapHandler()
-       go s.Config.Serve(s.Listener)
-}
-
-func (s *Server) wrapHandler() {
-       h := s.Config.Handler
-       if h == nil {
-               h = http.DefaultServeMux
-       }
-       s.Config.Handler = &waitGroupHandler{
-               s: s,
-               h: h,
-       }
+       s.wrap()
+       s.goServe()
 }
 
 // NewTLSServer starts and returns a new Server using TLS.
@@ -161,78 +138,155 @@ func NewTLSServer(handler http.Handler) *Server {
        return ts
 }
 
+type closeIdleTransport interface {
+       CloseIdleConnections()
+}
+
 // Close shuts down the server and blocks until all outstanding
 // requests on this server have completed.
 func (s *Server) Close() {
-       s.Listener.Close()
-       s.wg.Wait()
-       s.CloseClientConnections()
-       if t, ok := http.DefaultTransport.(*http.Transport); ok {
+       s.mu.Lock()
+       if !s.closed {
+               s.closed = true
+               s.Listener.Close()
+               s.Config.SetKeepAlivesEnabled(false)
+               for c, st := range s.conns {
+                       // Force-close any idle connections (those between
+                       // requests) and new connections (those which connected
+                       // but never sent a request). StateNew connections are
+                       // super rare and have only been seen (in
+                       // previously-flaky tests) in the case of
+                       // socket-late-binding races from the http Client
+                       // dialing this server and then getting an idle
+                       // connection before the dial completed.  There is thus
+                       // a connected connection in StateNew with no
+                       // associated Request. We only close StateIdle and
+                       // StateNew because they're not doing anything. It's
+                       // possible StateNew is about to do something in a few
+                       // milliseconds, but a previous CL to check again in a
+                       // few milliseconds wasn't liked (early versions of
+                       // https://golang.org/cl/15151) so now we just
+                       // forcefully close StateNew. The docs for Server.Close say
+                       // we wait for "oustanding requests", so we don't close things
+                       // in StateActive.
+                       if st == http.StateIdle || st == http.StateNew {
+                               s.closeConn(c)
+                       }
+               }
+               // If this server doesn't shut down in 20 seconds, tell the user why.
+               t := time.AfterFunc(20*time.Second, s.logCloseHangDebugInfo)
+               defer t.Stop()
+       }
+       s.mu.Unlock()
+
+       // Not part of httptest.Server's correctness, but assume most
+       // users of httptest.Server will be using the standard
+       // transport, so help them out and close any idle connections for them.
+       if t, ok := http.DefaultTransport.(closeIdleTransport); ok {
                t.CloseIdleConnections()
        }
+
+       s.wg.Wait()
 }
 
-// CloseClientConnections closes any currently open HTTP connections
-// to the test Server.
-func (s *Server) CloseClientConnections() {
-       hl, ok := s.Listener.(*historyListener)
-       if !ok {
-               return
+func (s *Server) logCloseHangDebugInfo() {
+       s.mu.Lock()
+       defer s.mu.Unlock()
+       var buf bytes.Buffer
+       buf.WriteString("httptest.Server blocked in Close after 5 seconds, waiting for connections:\n")
+       for c, st := range s.conns {
+               fmt.Fprintf(&buf, "  %T %p %v in state %v\n", c, c, c.RemoteAddr(), st)
        }
-       hl.Lock()
-       for _, conn := range hl.history {
-               conn.Close()
+       log.Print(buf.String())
+}
+
+// CloseClientConnections closes any open HTTP connections to the test Server.
+func (s *Server) CloseClientConnections() {
+       s.mu.Lock()
+       defer s.mu.Unlock()
+       for c := range s.conns {
+               s.closeConn(c)
        }
-       hl.Unlock()
 }
 
-// waitGroupHandler wraps a handler, incrementing and decrementing a
-// sync.WaitGroup on each request, to enable Server.Close to block
-// until outstanding requests are finished.
-type waitGroupHandler struct {
-       s *Server
-       h http.Handler // non-nil
+func (s *Server) goServe() {
+       s.wg.Add(1)
+       go func() {
+               defer s.wg.Done()
+               s.Config.Serve(s.Listener)
+       }()
+}
+
+// wrap installs the connection state-tracking hook to know which
+// connections are idle.
+func (s *Server) wrap() {
+       oldHook := s.Config.ConnState
+       s.Config.ConnState = func(c net.Conn, cs http.ConnState) {
+               s.mu.Lock()
+               defer s.mu.Unlock()
+               switch cs {
+               case http.StateNew:
+                       s.wg.Add(1)
+                       if _, exists := s.conns[c]; exists {
+                               panic("invalid state transition")
+                       }
+                       if s.conns == nil {
+                               s.conns = make(map[net.Conn]http.ConnState)
+                       }
+                       s.conns[c] = cs
+                       if s.closed {
+                               // Probably just a socket-late-binding dial from
+                               // the default transport that lost the race (and
+                               // thus this connection is now idle and will
+                               // never be used).
+                               s.closeConn(c)
+                       }
+               case http.StateActive:
+                       if oldState, ok := s.conns[c]; ok {
+                               if oldState != http.StateNew && oldState != http.StateIdle {
+                                       panic("invalid state transition")
+                               }
+                               s.conns[c] = cs
+                       }
+               case http.StateIdle:
+                       if oldState, ok := s.conns[c]; ok {
+                               if oldState != http.StateActive {
+                                       panic("invalid state transition")
+                               }
+                               s.conns[c] = cs
+                       }
+                       if s.closed {
+                               s.closeConn(c)
+                       }
+               case http.StateHijacked, http.StateClosed:
+                       s.forgetConn(c)
+               }
+               if oldHook != nil {
+                       oldHook(c, cs)
+               }
+       }
 }
 
-func (h *waitGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-       h.s.wg.Add(1)
-       defer h.s.wg.Done() // a defer, in case ServeHTTP below panics
-       h.h.ServeHTTP(w, r)
+// closeConn closes c. Except on plan9, which is special. See comment below.
+// s.mu must be held.
+func (s *Server) closeConn(c net.Conn) {
+       if runtime.GOOS == "plan9" {
+               // Go's Plan 9 net package isn't great at unblocking reads when
+               // their underlying TCP connections are closed.  Don't trust
+               // that that the ConnState state machine will get to
+               // StateClosed. Instead, just go there directly. Plan 9 may leak
+               // resources if the syscall doesn't end up returning. Oh well.
+               s.forgetConn(c)
+       }
+       go c.Close()
 }
 
-// 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/crypto/tls:
-// go run generate_cert.go  --rsa-bits 1024 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
-var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
-MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zANBgkqhkiG9w0BAQsFADAS
-MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
-MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
-iQKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9SjY1bIw4
-iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZBl2+XsDul
-rKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQABo2gwZjAO
-BgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUw
-AwEB/zAuBgNVHREEJzAlggtleGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAA
-AAAAATANBgkqhkiG9w0BAQsFAAOBgQCEcetwO59EWk7WiJsG4x8SY+UIAA+flUI9
-tyC4lNhbcF2Idq9greZwbYCqTTTr2XiRNSMLCOjKyI7ukPoPjo16ocHj+P3vZGfs
-h1fIw3cSS2OolhloGw/XM6RWPWtPAlGykKLciQrBru5NAPvCMsb/I1DAceTiotQM
-fblo6RBxUQ==
------END CERTIFICATE-----`)
-
-// localhostKey is the private key for localhostCert.
-var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
-MIICXgIBAAKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9
-SjY1bIw4iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZB
-l2+XsDulrKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQAB
-AoGAGRzwwir7XvBOAy5tM/uV6e+Zf6anZzus1s1Y1ClbjbE6HXbnWWF/wbZGOpet
-3Zm4vD6MXc7jpTLryzTQIvVdfQbRc6+MUVeLKwZatTXtdZrhu+Jk7hx0nTPy8Jcb
-uJqFk541aEw+mMogY/xEcfbWd6IOkp+4xqjlFLBEDytgbIECQQDvH/E6nk+hgN4H
-qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQcj2PprIMmPcQrooz8vp
-jy4SHEg1AkEA/v13/5M47K9vCxmb8QeD/asydfsgS5TeuNi8DoUBEmiSJwma7FXY
-fFUtxuvL7XvjwjN5B30pNEbc6Iuyt7y4MQJBAIt21su4b3sjXNueLKH85Q+phy2U
-fQtuUE9txblTu14q3N7gHRZB4ZMhFYyDy8CKrN2cPg/Fvyt0Xlp/DoCzjA0CQQDU
-y2ptGsuSmgUtWj3NM9xuwYPm+Z/F84K6+ARYiZ6PYj013sovGKUFfYAqVXVlxtIX
-qyUBnu3X9ps8ZfjLZO7BAkEAlT4R5Yl6cGhaJQYZHOde3JEMhNRcVFMO8dJDaFeo
-f9Oeos0UUothgiDktdQHxdNEwLjQf7lJJBzV+5OtwswCWA==
------END RSA PRIVATE KEY-----`)
+// forgetConn removes c from the set of tracked conns and decrements it from the
+// waitgroup, unless it was previously removed.
+// s.mu must be held.
+func (s *Server) forgetConn(c net.Conn) {
+       if _, ok := s.conns[c]; ok {
+               delete(s.conns, c)
+               s.wg.Done()
+       }
+}
index 500a9f0b80000b93a1c85f9f6fd1689e487c7239..6ffc671e575241ac332af94148eba2da24b33e77 100644 (file)
@@ -5,7 +5,9 @@
 package httptest
 
 import (
+       "bufio"
        "io/ioutil"
+       "net"
        "net/http"
        "testing"
 )
@@ -27,3 +29,58 @@ func TestServer(t *testing.T) {
                t.Errorf("got %q, want hello", string(got))
        }
 }
+
+// Issue 12781
+func TestGetAfterClose(t *testing.T) {
+       ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               w.Write([]byte("hello"))
+       }))
+
+       res, err := http.Get(ts.URL)
+       if err != nil {
+               t.Fatal(err)
+       }
+       got, err := ioutil.ReadAll(res.Body)
+       if err != nil {
+               t.Fatal(err)
+       }
+       if string(got) != "hello" {
+               t.Fatalf("got %q, want hello", string(got))
+       }
+
+       ts.Close()
+
+       res, err = http.Get(ts.URL)
+       if err == nil {
+               body, _ := ioutil.ReadAll(res.Body)
+               t.Fatalf("Unexected response after close: %v, %v, %s", res.Status, res.Header, body)
+       }
+}
+
+func TestServerCloseBlocking(t *testing.T) {
+       ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               w.Write([]byte("hello"))
+       }))
+       dial := func() net.Conn {
+               c, err := net.Dial("tcp", ts.Listener.Addr().String())
+               if err != nil {
+                       t.Fatal(err)
+               }
+               return c
+       }
+
+       // Keep one connection in StateNew (connected, but not sending anything)
+       cnew := dial()
+       defer cnew.Close()
+
+       // Keep one connection in StateIdle (idle after a request)
+       cidle := dial()
+       defer cidle.Close()
+       cidle.Write([]byte("HEAD / HTTP/1.1\r\nHost: foo\r\n\r\n"))
+       _, err := http.ReadResponse(bufio.NewReader(cidle), nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       ts.Close() // test we don't hang here forever.
+}
index ca2d1cde924224d9d19bf0d4419c298501f10de9..e22cc66dbfccfee8e211832226e2e009e995eb79 100644 (file)
@@ -25,10 +25,10 @@ import (
 func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) {
        var buf bytes.Buffer
        if _, err = buf.ReadFrom(b); err != nil {
-               return nil, nil, err
+               return nil, b, err
        }
        if err = b.Close(); err != nil {
-               return nil, nil, err
+               return nil, b, err
        }
        return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewReader(buf.Bytes())), nil
 }
@@ -55,9 +55,9 @@ func (b neverEnding) Read(p []byte) (n int, err error) {
        return len(p), nil
 }
 
-// DumpRequestOut is like DumpRequest but includes
-// headers that the standard http.Transport adds,
-// such as User-Agent.
+// DumpRequestOut is like DumpRequest but for outgoing client requests. It
+// includes any headers that the standard http.Transport adds, such as
+// User-Agent.
 func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
        save := req.Body
        dummyBody := false
@@ -175,13 +175,22 @@ func dumpAsReceived(req *http.Request, w io.Writer) error {
        return nil
 }
 
-// DumpRequest returns the as-received wire representation of req,
-// optionally including the request body, for debugging.
-// DumpRequest is semantically a no-op, but in order to
-// dump the body, it reads the body data into memory and
-// changes req.Body to refer to the in-memory copy.
+// DumpRequest returns the given request in its HTTP/1.x wire
+// representation. It should only be used by servers to debug client
+// requests. The returned representation is an approximation only;
+// some details of the initial request are lost while parsing it into
+// an http.Request. In particular, the order and case of header field
+// names are lost. The order of values in multi-valued headers is kept
+// intact. HTTP/2 requests are dumped in HTTP/1.x form, not in their
+// original binary representations.
+//
+// If body is true, DumpRequest also returns the body. To do so, it
+// consumes req.Body and then replaces it with a new io.ReadCloser
+// that yields the same bytes. If DumpRequest returns an error,
+// the state of req is undefined.
+//
 // The documentation for http.Request.Write details which fields
-// of req are used.
+// of req are included in the dump.
 func DumpRequest(req *http.Request, body bool) (dump []byte, err error) {
        save := req.Body
        if !body || req.Body == nil {
@@ -189,21 +198,35 @@ func DumpRequest(req *http.Request, body bool) (dump []byte, err error) {
        } else {
                save, req.Body, err = drainBody(req.Body)
                if err != nil {
-                       return
+                       return nil, err
                }
        }
 
        var b bytes.Buffer
 
+       // By default, print out the unmodified req.RequestURI, which
+       // is always set for incoming server requests. But because we
+       // previously used req.URL.RequestURI and the docs weren't
+       // always so clear about when to use DumpRequest vs
+       // DumpRequestOut, fall back to the old way if the caller
+       // provides a non-server Request.
+       reqURI := req.RequestURI
+       if reqURI == "" {
+               reqURI = req.URL.RequestURI()
+       }
+
        fmt.Fprintf(&b, "%s %s HTTP/%d.%d\r\n", valueOrDefault(req.Method, "GET"),
-               req.URL.RequestURI(), req.ProtoMajor, req.ProtoMinor)
+               reqURI, req.ProtoMajor, req.ProtoMinor)
 
-       host := req.Host
-       if host == "" && req.URL != nil {
-               host = req.URL.Host
-       }
-       if host != "" {
-               fmt.Fprintf(&b, "Host: %s\r\n", host)
+       absRequestURI := strings.HasPrefix(req.RequestURI, "http://") || strings.HasPrefix(req.RequestURI, "https://")
+       if !absRequestURI {
+               host := req.Host
+               if host == "" && req.URL != nil {
+                       host = req.URL.Host
+               }
+               if host != "" {
+                       fmt.Fprintf(&b, "Host: %s\r\n", host)
+               }
        }
 
        chunked := len(req.TransferEncoding) > 0 && req.TransferEncoding[0] == "chunked"
@@ -269,7 +292,7 @@ func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) {
        } else {
                save, resp.Body, err = drainBody(resp.Body)
                if err != nil {
-                       return
+                       return nil, err
                }
        }
        err = resp.Write(&b)
index ae67e983ae9db6423e56eaa28d7f6700c6c21ca6..46bf521723afbfc88098c17a913edc8426819057 100644 (file)
@@ -5,6 +5,7 @@
 package httputil
 
 import (
+       "bufio"
        "bytes"
        "fmt"
        "io"
@@ -135,6 +136,14 @@ var dumpTests = []dumpTest{
                        "Accept-Encoding: gzip\r\n\r\n" +
                        strings.Repeat("a", 8193),
        },
+
+       {
+               Req: *mustReadRequest("GET http://foo.com/ HTTP/1.1\r\n" +
+                       "User-Agent: blah\r\n\r\n"),
+               NoBody: true,
+               WantDump: "GET http://foo.com/ HTTP/1.1\r\n" +
+                       "User-Agent: blah\r\n\r\n",
+       },
 }
 
 func TestDumpRequest(t *testing.T) {
@@ -211,6 +220,14 @@ func mustNewRequest(method, url string, body io.Reader) *http.Request {
        return req
 }
 
+func mustReadRequest(s string) *http.Request {
+       req, err := http.ReadRequest(bufio.NewReader(strings.NewReader(s)))
+       if err != nil {
+               panic(err)
+       }
+       return req
+}
+
 var dumpResTests = []struct {
        res  *http.Response
        body bool
diff --git a/libgo/go/net/http/httputil/example_test.go b/libgo/go/net/http/httputil/example_test.go
new file mode 100644 (file)
index 0000000..8fb1a2d
--- /dev/null
@@ -0,0 +1,125 @@
+// Copyright 2015 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 ignore
+
+package httputil_test
+
+import (
+       "fmt"
+       "io/ioutil"
+       "log"
+       "net/http"
+       "net/http/httptest"
+       "net/http/httputil"
+       "net/url"
+       "strings"
+)
+
+func ExampleDumpRequest() {
+       ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               dump, err := httputil.DumpRequest(r, true)
+               if err != nil {
+                       http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
+                       return
+               }
+
+               fmt.Fprintf(w, "%q", dump)
+       }))
+       defer ts.Close()
+
+       const body = "Go is a general-purpose language designed with systems programming in mind."
+       req, err := http.NewRequest("POST", ts.URL, strings.NewReader(body))
+       if err != nil {
+               log.Fatal(err)
+       }
+       req.Host = "www.example.org"
+       resp, err := http.DefaultClient.Do(req)
+       if err != nil {
+               log.Fatal(err)
+       }
+       defer resp.Body.Close()
+
+       b, err := ioutil.ReadAll(resp.Body)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       fmt.Printf("%s", b)
+
+       // Output:
+       // "POST / HTTP/1.1\r\nHost: www.example.org\r\nAccept-Encoding: gzip\r\nUser-Agent: Go-http-client/1.1\r\n\r\nGo is a general-purpose language designed with systems programming in mind."
+}
+
+func ExampleDumpRequestOut() {
+       const body = "Go is a general-purpose language designed with systems programming in mind."
+       req, err := http.NewRequest("PUT", "http://www.example.org", strings.NewReader(body))
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       dump, err := httputil.DumpRequestOut(req, true)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       fmt.Printf("%q", dump)
+
+       // Output:
+       // "PUT / HTTP/1.1\r\nHost: www.example.org\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 75\r\nAccept-Encoding: gzip\r\n\r\nGo is a general-purpose language designed with systems programming in mind."
+}
+
+func ExampleDumpResponse() {
+       const body = "Go is a general-purpose language designed with systems programming in mind."
+       ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               w.Header().Set("Date", "Wed, 19 Jul 1972 19:00:00 GMT")
+               fmt.Fprintln(w, body)
+       }))
+       defer ts.Close()
+
+       resp, err := http.Get(ts.URL)
+       if err != nil {
+               log.Fatal(err)
+       }
+       defer resp.Body.Close()
+
+       dump, err := httputil.DumpResponse(resp, true)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       fmt.Printf("%q", dump)
+
+       // Output:
+       // "HTTP/1.1 200 OK\r\nContent-Length: 76\r\nContent-Type: text/plain; charset=utf-8\r\nDate: Wed, 19 Jul 1972 19:00:00 GMT\r\n\r\nGo is a general-purpose language designed with systems programming in mind.\n"
+}
+
+func ExampleReverseProxy() {
+       backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               fmt.Fprintln(w, "this call was relayed by the reverse proxy")
+       }))
+       defer backendServer.Close()
+
+       rpURL, err := url.Parse(backendServer.URL)
+       if err != nil {
+               log.Fatal(err)
+       }
+       frontendProxy := httptest.NewServer(httputil.NewSingleHostReverseProxy(rpURL))
+       defer frontendProxy.Close()
+
+       resp, err := http.Get(frontendProxy.URL)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       b, err := ioutil.ReadAll(resp.Body)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       fmt.Printf("%s", b)
+
+       // Output:
+       // this call was relayed by the reverse proxy
+}
index c8e113221c45dfa1fca62effc4189c7a3983450c..4dba352a4fa5110f94c2e3a012533fc2784e639f 100644 (file)
@@ -46,6 +46,18 @@ type ReverseProxy struct {
        // If nil, logging goes to os.Stderr via the log package's
        // standard logger.
        ErrorLog *log.Logger
+
+       // BufferPool optionally specifies a buffer pool to
+       // get byte slices for use by io.CopyBuffer when
+       // copying HTTP response bodies.
+       BufferPool BufferPool
+}
+
+// A BufferPool is an interface for getting and returning temporary
+// byte slices for use by io.CopyBuffer.
+type BufferPool interface {
+       Get() []byte
+       Put([]byte)
 }
 
 func singleJoiningSlash(a, b string) string {
@@ -60,10 +72,13 @@ func singleJoiningSlash(a, b string) string {
        return a + b
 }
 
-// NewSingleHostReverseProxy returns a new ReverseProxy that rewrites
+// NewSingleHostReverseProxy returns a new ReverseProxy that routes
 // URLs to the scheme, host, and base path provided in target. If the
 // target's path is "/base" and the incoming request was for "/dir",
 // the target request will be for /base/dir.
+// NewSingleHostReverseProxy does not rewrite the Host header.
+// To rewrite Host headers, use ReverseProxy directly with a custom
+// Director policy.
 func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy {
        targetQuery := target.RawQuery
        director := func(req *http.Request) {
@@ -242,7 +257,14 @@ func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) {
                }
        }
 
-       io.Copy(dst, src)
+       var buf []byte
+       if p.BufferPool != nil {
+               buf = p.BufferPool.Get()
+       }
+       io.CopyBuffer(dst, src, buf)
+       if p.BufferPool != nil {
+               p.BufferPool.Put(buf)
+       }
 }
 
 func (p *ReverseProxy) logf(format string, args ...interface{}) {
index 80a26abe414f1b1252234839ba0f67259a3ac3dc..7f203d878f544ec5d222c6b91447542411296fe5 100644 (file)
@@ -8,14 +8,17 @@ package httputil
 
 import (
        "bufio"
+       "bytes"
+       "io"
        "io/ioutil"
        "log"
        "net/http"
        "net/http/httptest"
        "net/url"
        "reflect"
-       "runtime"
+       "strconv"
        "strings"
+       "sync"
        "testing"
        "time"
 )
@@ -102,7 +105,6 @@ func TestReverseProxy(t *testing.T) {
        if g, e := res.Trailer.Get("X-Trailer"), "trailer_value"; g != e {
                t.Errorf("Trailer(X-Trailer) = %q ; want %q", g, e)
        }
-
 }
 
 func TestXForwardedFor(t *testing.T) {
@@ -225,10 +227,7 @@ func TestReverseProxyFlushInterval(t *testing.T) {
        }
 }
 
-func TestReverseProxyCancellation(t *testing.T) {
-       if runtime.GOOS == "plan9" {
-               t.Skip("skipping test; see https://golang.org/issue/9554")
-       }
+func TestReverseProxyCancelation(t *testing.T) {
        const backendResponse = "I am the backend"
 
        reqInFlight := make(chan struct{})
@@ -320,3 +319,108 @@ func TestNilBody(t *testing.T) {
                t.Errorf("Got %q; want %q", slurp, "hi")
        }
 }
+
+type bufferPool struct {
+       get func() []byte
+       put func([]byte)
+}
+
+func (bp bufferPool) Get() []byte  { return bp.get() }
+func (bp bufferPool) Put(v []byte) { bp.put(v) }
+
+func TestReverseProxyGetPutBuffer(t *testing.T) {
+       const msg = "hi"
+       backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               io.WriteString(w, msg)
+       }))
+       defer backend.Close()
+
+       backendURL, err := url.Parse(backend.URL)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       var (
+               mu  sync.Mutex
+               log []string
+       )
+       addLog := func(event string) {
+               mu.Lock()
+               defer mu.Unlock()
+               log = append(log, event)
+       }
+       rp := NewSingleHostReverseProxy(backendURL)
+       const size = 1234
+       rp.BufferPool = bufferPool{
+               get: func() []byte {
+                       addLog("getBuf")
+                       return make([]byte, size)
+               },
+               put: func(p []byte) {
+                       addLog("putBuf-" + strconv.Itoa(len(p)))
+               },
+       }
+       frontend := httptest.NewServer(rp)
+       defer frontend.Close()
+
+       req, _ := http.NewRequest("GET", frontend.URL, nil)
+       req.Close = true
+       res, err := http.DefaultClient.Do(req)
+       if err != nil {
+               t.Fatalf("Get: %v", err)
+       }
+       slurp, err := ioutil.ReadAll(res.Body)
+       res.Body.Close()
+       if err != nil {
+               t.Fatalf("reading body: %v", err)
+       }
+       if string(slurp) != msg {
+               t.Errorf("msg = %q; want %q", slurp, msg)
+       }
+       wantLog := []string{"getBuf", "putBuf-" + strconv.Itoa(size)}
+       mu.Lock()
+       defer mu.Unlock()
+       if !reflect.DeepEqual(log, wantLog) {
+               t.Errorf("Log events = %q; want %q", log, wantLog)
+       }
+}
+
+func TestReverseProxy_Post(t *testing.T) {
+       const backendResponse = "I am the backend"
+       const backendStatus = 200
+       var requestBody = bytes.Repeat([]byte("a"), 1<<20)
+       backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               slurp, err := ioutil.ReadAll(r.Body)
+               if err != nil {
+                       t.Errorf("Backend body read = %v", err)
+               }
+               if len(slurp) != len(requestBody) {
+                       t.Errorf("Backend read %d request body bytes; want %d", len(slurp), len(requestBody))
+               }
+               if !bytes.Equal(slurp, requestBody) {
+                       t.Error("Backend read wrong request body.") // 1MB; omitting details
+               }
+               w.Write([]byte(backendResponse))
+       }))
+       defer backend.Close()
+       backendURL, err := url.Parse(backend.URL)
+       if err != nil {
+               t.Fatal(err)
+       }
+       proxyHandler := NewSingleHostReverseProxy(backendURL)
+       frontend := httptest.NewServer(proxyHandler)
+       defer frontend.Close()
+
+       postReq, _ := http.NewRequest("POST", frontend.URL, bytes.NewReader(requestBody))
+       res, err := http.DefaultClient.Do(postReq)
+       if err != nil {
+               t.Fatalf("Do: %v", err)
+       }
+       if g, e := res.StatusCode, backendStatus; g != e {
+               t.Errorf("got res.StatusCode %d; expected %d", g, e)
+       }
+       bodyBytes, _ := ioutil.ReadAll(res.Body)
+       if g, e := string(bodyBytes), backendResponse; g != e {
+               t.Errorf("got body %q; expected %q", g, e)
+       }
+}
index 6d7c69874d9d6f6acbce282a28cb80cd34d070a9..2e62c00d5db5013e9e73c26cc59179b385f3e261 100644 (file)
@@ -44,7 +44,7 @@ type chunkedReader struct {
 func (cr *chunkedReader) beginChunk() {
        // chunk-size CRLF
        var line []byte
-       line, cr.err = readLine(cr.r)
+       line, cr.err = readChunkLine(cr.r)
        if cr.err != nil {
                return
        }
@@ -104,10 +104,11 @@ func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
 
 // Read a line of bytes (up to \n) from b.
 // Give up if the line exceeds maxLineLength.
-// The returned bytes are a pointer into storage in
-// the bufio, so they are only valid until the next bufio read.
-func readLine(b *bufio.Reader) (p []byte, err error) {
-       if p, err = b.ReadSlice('\n'); err != nil {
+// The returned bytes are owned by the bufio.Reader
+// so they are only valid until the next bufio read.
+func readChunkLine(b *bufio.Reader) ([]byte, error) {
+       p, err := b.ReadSlice('\n')
+       if err != nil {
                // We always know when EOF is coming.
                // If the caller asked for a line, there should be a line.
                if err == io.EOF {
@@ -120,7 +121,12 @@ func readLine(b *bufio.Reader) (p []byte, err error) {
        if len(p) >= maxLineLength {
                return nil, ErrLineTooLong
        }
-       return trimTrailingWhitespace(p), nil
+       p = trimTrailingWhitespace(p)
+       p, err = removeChunkExtension(p)
+       if err != nil {
+               return nil, err
+       }
+       return p, nil
 }
 
 func trimTrailingWhitespace(b []byte) []byte {
@@ -134,6 +140,23 @@ func isASCIISpace(b byte) bool {
        return b == ' ' || b == '\t' || b == '\n' || b == '\r'
 }
 
+// removeChunkExtension removes any chunk-extension from p.
+// For example,
+//     "0" => "0"
+//     "0;token" => "0"
+//     "0;token=val" => "0"
+//     `0;token="quoted string"` => "0"
+func removeChunkExtension(p []byte) ([]byte, error) {
+       semi := bytes.IndexByte(p, ';')
+       if semi == -1 {
+               return p, nil
+       }
+       // TODO: care about exact syntax of chunk extensions? We're
+       // ignoring and stripping them anyway. For now just never
+       // return an error.
+       return p[:semi], nil
+}
+
 // NewChunkedWriter returns a new chunkedWriter that translates writes into HTTP
 // "chunked" format before writing them to w. Closing the returned chunkedWriter
 // sends the final 0-length chunk that marks the end of the stream.
@@ -197,8 +220,7 @@ type FlushAfterChunkWriter struct {
 }
 
 func parseHexUint(v []byte) (n uint64, err error) {
-       for _, b := range v {
-               n <<= 4
+       for i, b := range v {
                switch {
                case '0' <= b && b <= '9':
                        b = b - '0'
@@ -209,6 +231,10 @@ func parseHexUint(v []byte) (n uint64, err error) {
                default:
                        return 0, errors.New("invalid byte in chunk length")
                }
+               if i == 16 {
+                       return 0, errors.New("http chunk length too large")
+               }
+               n <<= 4
                n |= uint64(b)
        }
        return
index ebc626ea9d0ec368d5028ffb04b6f39024dedd14..a136dc99a65fc82271839e8f1245539a50d09601 100644 (file)
@@ -139,18 +139,49 @@ func TestChunkReaderAllocs(t *testing.T) {
 }
 
 func TestParseHexUint(t *testing.T) {
+       type testCase struct {
+               in      string
+               want    uint64
+               wantErr string
+       }
+       tests := []testCase{
+               {"x", 0, "invalid byte in chunk length"},
+               {"0000000000000000", 0, ""},
+               {"0000000000000001", 1, ""},
+               {"ffffffffffffffff", 1<<64 - 1, ""},
+               {"000000000000bogus", 0, "invalid byte in chunk length"},
+               {"00000000000000000", 0, "http chunk length too large"}, // could accept if we wanted
+               {"10000000000000000", 0, "http chunk length too large"},
+               {"00000000000000001", 0, "http chunk length too large"}, // could accept if we wanted
+       }
        for i := uint64(0); i <= 1234; i++ {
-               line := []byte(fmt.Sprintf("%x", i))
-               got, err := parseHexUint(line)
-               if err != nil {
-                       t.Fatalf("on %d: %v", i, err)
-               }
-               if got != i {
-                       t.Errorf("for input %q = %d; want %d", line, got, i)
+               tests = append(tests, testCase{in: fmt.Sprintf("%x", i), want: i})
+       }
+       for _, tt := range tests {
+               got, err := parseHexUint([]byte(tt.in))
+               if tt.wantErr != "" {
+                       if !strings.Contains(fmt.Sprint(err), tt.wantErr) {
+                               t.Errorf("parseHexUint(%q) = %v, %v; want error %q", tt.in, got, err, tt.wantErr)
+                       }
+               } else {
+                       if err != nil || got != tt.want {
+                               t.Errorf("parseHexUint(%q) = %v, %v; want %v", tt.in, got, err, tt.want)
+                       }
                }
        }
-       _, err := parseHexUint([]byte("bogus"))
-       if err == nil {
-               t.Error("expected error on bogus input")
+}
+
+func TestChunkReadingIgnoresExtensions(t *testing.T) {
+       in := "7;ext=\"some quoted string\"\r\n" + // token=quoted string
+               "hello, \r\n" +
+               "17;someext\r\n" + // token without value
+               "world! 0123456789abcdef\r\n" +
+               "0;someextension=sometoken\r\n" // token=token
+       data, err := ioutil.ReadAll(NewChunkedReader(strings.NewReader(in)))
+       if err != nil {
+               t.Fatalf("ReadAll = %q, %v", data, err)
+       }
+       if g, e := string(data), "hello, world! 0123456789abcdef"; g != e {
+               t.Errorf("read %q; want %q", g, e)
        }
 }
diff --git a/libgo/go/net/http/internal/testcert.go b/libgo/go/net/http/internal/testcert.go
new file mode 100644 (file)
index 0000000..4078909
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2015 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 internal
+
+// LocalhostCert is a PEM-encoded TLS cert with SAN IPs
+// "127.0.0.1" and "[::1]", expiring at Jan 29 16:00:00 2084 GMT.
+// generated from src/crypto/tls:
+// go run generate_cert.go  --rsa-bits 1024 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
+var LocalhostCert = []byte(`-----BEGIN CERTIFICATE-----
+MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zANBgkqhkiG9w0BAQsFADAS
+MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
+MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
+iQKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9SjY1bIw4
+iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZBl2+XsDul
+rKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQABo2gwZjAO
+BgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUw
+AwEB/zAuBgNVHREEJzAlggtleGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAA
+AAAAATANBgkqhkiG9w0BAQsFAAOBgQCEcetwO59EWk7WiJsG4x8SY+UIAA+flUI9
+tyC4lNhbcF2Idq9greZwbYCqTTTr2XiRNSMLCOjKyI7ukPoPjo16ocHj+P3vZGfs
+h1fIw3cSS2OolhloGw/XM6RWPWtPAlGykKLciQrBru5NAPvCMsb/I1DAceTiotQM
+fblo6RBxUQ==
+-----END CERTIFICATE-----`)
+
+// LocalhostKey is the private key for localhostCert.
+var LocalhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
+MIICXgIBAAKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9
+SjY1bIw4iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZB
+l2+XsDulrKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQAB
+AoGAGRzwwir7XvBOAy5tM/uV6e+Zf6anZzus1s1Y1ClbjbE6HXbnWWF/wbZGOpet
+3Zm4vD6MXc7jpTLryzTQIvVdfQbRc6+MUVeLKwZatTXtdZrhu+Jk7hx0nTPy8Jcb
+uJqFk541aEw+mMogY/xEcfbWd6IOkp+4xqjlFLBEDytgbIECQQDvH/E6nk+hgN4H
+qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQcj2PprIMmPcQrooz8vp
+jy4SHEg1AkEA/v13/5M47K9vCxmb8QeD/asydfsgS5TeuNi8DoUBEmiSJwma7FXY
+fFUtxuvL7XvjwjN5B30pNEbc6Iuyt7y4MQJBAIt21su4b3sjXNueLKH85Q+phy2U
+fQtuUE9txblTu14q3N7gHRZB4ZMhFYyDy8CKrN2cPg/Fvyt0Xlp/DoCzjA0CQQDU
+y2ptGsuSmgUtWj3NM9xuwYPm+Z/F84K6+ARYiZ6PYj013sovGKUFfYAqVXVlxtIX
+qyUBnu3X9ps8ZfjLZO7BAkEAlT4R5Yl6cGhaJQYZHOde3JEMhNRcVFMO8dJDaFeo
+f9Oeos0UUothgiDktdQHxdNEwLjQf7lJJBzV+5OtwswCWA==
+-----END RSA PRIVATE KEY-----`)
index 50b14f8b32587b07e0db73f68ca155b1ce2adc46..52b6481c14e725b2229e91916c1298e55b4a3cff 100644 (file)
@@ -167,3 +167,17 @@ func tokenEqual(t1, t2 string) bool {
        }
        return true
 }
+
+// isLWS reports whether b is linear white space, according
+// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
+//      LWS            = [CRLF] 1*( SP | HT )
+func isLWS(b byte) bool { return b == ' ' || b == '\t' }
+
+// isCTL reports whether b is a control byte, according
+// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
+//      CTL            = <any US-ASCII control character
+//                       (octets 0 - 31) and DEL (127)>
+func isCTL(b byte) bool {
+       const del = 0x7f // a CTL
+       return b < ' ' || b == del
+}
index 12eea6f0e119c1eaf5d9b955493ffb6d271fcf84..299cd7b2d2f231c9b5ef75b964d23f595528d8fb 100644 (file)
@@ -5,6 +5,7 @@
 package http_test
 
 import (
+       "flag"
        "fmt"
        "net/http"
        "os"
@@ -15,6 +16,8 @@ import (
        "time"
 )
 
+var flaky = flag.Bool("flaky", false, "run known-flaky tests too")
+
 func TestMain(m *testing.M) {
        v := m.Run()
        if v == 0 && goroutineLeaked() {
@@ -79,6 +82,21 @@ func goroutineLeaked() bool {
        return true
 }
 
+// setParallel marks t as a parallel test if we're in short mode
+// (all.bash), but as a serial test otherwise. Using t.Parallel isn't
+// compatible with the afterTest func in non-short mode.
+func setParallel(t *testing.T) {
+       if testing.Short() {
+               t.Parallel()
+       }
+}
+
+func setFlaky(t *testing.T, issue int) {
+       if !*flaky {
+               t.Skipf("skipping known flaky test; see golang.org/issue/%d", issue)
+       }
+}
+
 func afterTest(t testing.TB) {
        http.DefaultTransport.(*http.Transport).CloseIdleConnections()
        if testing.Short() {
diff --git a/libgo/go/net/http/method.go b/libgo/go/net/http/method.go
new file mode 100644 (file)
index 0000000..b74f960
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2015 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 http
+
+// Common HTTP methods.
+//
+// Unless otherwise noted, these are defined in RFC 7231 section 4.3.
+const (
+       MethodGet     = "GET"
+       MethodHead    = "HEAD"
+       MethodPost    = "POST"
+       MethodPut     = "PUT"
+       MethodPatch   = "PATCH" // RFC 5741
+       MethodDelete  = "DELETE"
+       MethodConnect = "CONNECT"
+       MethodOptions = "OPTIONS"
+       MethodTrace   = "TRACE"
+)
index 8994392b1e4ba694dff7b05570cc39fd8f24b1c1..7262c6c10163106cdb27c084c34f6d1277db756b 100644 (file)
@@ -79,6 +79,17 @@ func Cmdline(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
 }
 
+func sleep(w http.ResponseWriter, d time.Duration) {
+       var clientGone <-chan bool
+       if cn, ok := w.(http.CloseNotifier); ok {
+               clientGone = cn.CloseNotify()
+       }
+       select {
+       case <-time.After(d):
+       case <-clientGone:
+       }
+}
+
 // Profile responds with the pprof-formatted cpu profile.
 // The package initialization registers it as /debug/pprof/profile.
 func Profile(w http.ResponseWriter, r *http.Request) {
@@ -99,7 +110,7 @@ func Profile(w http.ResponseWriter, r *http.Request) {
                fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
                return
        }
-       time.Sleep(time.Duration(sec) * time.Second)
+       sleep(w, time.Duration(sec)*time.Second)
        pprof.StopCPUProfile()
 }
 
@@ -125,7 +136,7 @@ func Trace(w http.ResponseWriter, r *http.Request) {
                        fmt.Fprintf(w, "Could not enable tracing: %s\n", err)
                        return
                }
-               time.Sleep(time.Duration(sec) * time.Second)
+               sleep(w, time.Duration(sec)*time.Second)
                trace.Stop()
        */
 }
index 31fe45a4edb7d51522156bb226daf0a58391fb15..16c5bb43ac4d4c7b7974dfa0c6e1c50c0c28eef3 100644 (file)
@@ -90,8 +90,11 @@ type Request struct {
        // request.
        URL *url.URL
 
-       // The protocol version for incoming requests.
-       // Client requests always use HTTP/1.1.
+       // The protocol version for incoming server requests.
+       //
+       // For client requests these fields are ignored. The HTTP
+       // client code always uses either HTTP/1.1 or HTTP/2.
+       // See the docs on Transport for details.
        Proto      string // "HTTP/1.0"
        ProtoMajor int    // 1
        ProtoMinor int    // 0
@@ -354,7 +357,7 @@ const defaultUserAgent = "Go-http-client/1.1"
 // hasn't been set to "identity", Write adds "Transfer-Encoding:
 // chunked" to the header. Body is closed after it is sent.
 func (r *Request) Write(w io.Writer) error {
-       return r.write(w, false, nil)
+       return r.write(w, false, nil, nil)
 }
 
 // WriteProxy is like Write but writes the request in the form
@@ -364,11 +367,16 @@ func (r *Request) Write(w io.Writer) error {
 // In either case, WriteProxy also writes a Host header, using
 // either r.Host or r.URL.Host.
 func (r *Request) WriteProxy(w io.Writer) error {
-       return r.write(w, true, nil)
+       return r.write(w, true, nil, nil)
 }
 
+// errMissingHost is returned by Write when there is no Host or URL present in
+// the Request.
+var errMissingHost = errors.New("http: Request.Write on Request with no Host or URL set")
+
 // extraHeaders may be nil
-func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) error {
+// waitForContinue may be nil
+func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitForContinue func() bool) error {
        // Find the target host. Prefer the Host: header, but if that
        // is not given, use the host from the request URL.
        //
@@ -376,7 +384,7 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err
        host := cleanHost(req.Host)
        if host == "" {
                if req.URL == nil {
-                       return errors.New("http: Request.Write on Request with no Host or URL set")
+                       return errMissingHost
                }
                host = cleanHost(req.URL.Host)
        }
@@ -419,10 +427,8 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err
        // Use the defaultUserAgent unless the Header contains one, which
        // may be blank to not send the header.
        userAgent := defaultUserAgent
-       if req.Header != nil {
-               if ua := req.Header["User-Agent"]; len(ua) > 0 {
-                       userAgent = ua[0]
-               }
+       if _, ok := req.Header["User-Agent"]; ok {
+               userAgent = req.Header.Get("User-Agent")
        }
        if userAgent != "" {
                _, err = fmt.Fprintf(w, "User-Agent: %s\r\n", userAgent)
@@ -458,6 +464,21 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err
                return err
        }
 
+       // Flush and wait for 100-continue if expected.
+       if waitForContinue != nil {
+               if bw, ok := w.(*bufio.Writer); ok {
+                       err = bw.Flush()
+                       if err != nil {
+                               return err
+                       }
+               }
+
+               if !waitForContinue() {
+                       req.closeBody()
+                       return nil
+               }
+       }
+
        // Write body and trailer
        err = tw.WriteBody(w)
        if err != nil {
@@ -531,6 +552,23 @@ func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
        return major, minor, true
 }
 
+func validMethod(method string) bool {
+       /*
+            Method         = "OPTIONS"                ; Section 9.2
+                           | "GET"                    ; Section 9.3
+                           | "HEAD"                   ; Section 9.4
+                           | "POST"                   ; Section 9.5
+                           | "PUT"                    ; Section 9.6
+                           | "DELETE"                 ; Section 9.7
+                           | "TRACE"                  ; Section 9.8
+                           | "CONNECT"                ; Section 9.9
+                           | extension-method
+          extension-method = token
+            token          = 1*<any CHAR except CTLs or separators>
+       */
+       return len(method) > 0 && strings.IndexFunc(method, isNotToken) == -1
+}
+
 // NewRequest returns a new Request given a method, URL, and optional body.
 //
 // If the provided body is also an io.Closer, the returned
@@ -544,6 +582,15 @@ func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
 // type's documentation for the difference between inbound and outbound
 // request fields.
 func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
+       if method == "" {
+               // We document that "" means "GET" for Request.Method, and people have
+               // relied on that from NewRequest, so keep that working.
+               // We still enforce validMethod for non-empty methods.
+               method = "GET"
+       }
+       if !validMethod(method) {
+               return nil, fmt.Errorf("net/http: invalid method %q", method)
+       }
        u, err := url.Parse(urlStr)
        if err != nil {
                return nil, err
@@ -643,8 +690,15 @@ func putTextprotoReader(r *textproto.Reader) {
 }
 
 // ReadRequest reads and parses an incoming request from b.
-func ReadRequest(b *bufio.Reader) (req *Request, err error) {
+func ReadRequest(b *bufio.Reader) (req *Request, err error) { return readRequest(b, deleteHostHeader) }
+
+// Constants for readRequest's deleteHostHeader parameter.
+const (
+       deleteHostHeader = true
+       keepHostHeader   = false
+)
 
+func readRequest(b *bufio.Reader, deleteHostHeader bool) (req *Request, err error) {
        tp := newTextprotoReader(b)
        req = new(Request)
 
@@ -711,7 +765,9 @@ func ReadRequest(b *bufio.Reader) (req *Request, err error) {
        if req.Host == "" {
                req.Host = req.Header.get("Host")
        }
-       delete(req.Header, "Host")
+       if deleteHostHeader {
+               delete(req.Header, "Host")
+       }
 
        fixPragmaCacheControl(req.Header)
 
@@ -1006,3 +1062,102 @@ func (r *Request) closeBody() {
                r.Body.Close()
        }
 }
+
+func (r *Request) isReplayable() bool {
+       if r.Body == nil {
+               switch valueOrDefault(r.Method, "GET") {
+               case "GET", "HEAD", "OPTIONS", "TRACE":
+                       return true
+               }
+       }
+       return false
+}
+
+func validHostHeader(h string) bool {
+       // The latests spec is actually this:
+       //
+       // http://tools.ietf.org/html/rfc7230#section-5.4
+       //     Host = uri-host [ ":" port ]
+       //
+       // Where uri-host is:
+       //     http://tools.ietf.org/html/rfc3986#section-3.2.2
+       //
+       // But we're going to be much more lenient for now and just
+       // search for any byte that's not a valid byte in any of those
+       // expressions.
+       for i := 0; i < len(h); i++ {
+               if !validHostByte[h[i]] {
+                       return false
+               }
+       }
+       return true
+}
+
+// See the validHostHeader comment.
+var validHostByte = [256]bool{
+       '0': true, '1': true, '2': true, '3': true, '4': true, '5': true, '6': true, '7': true,
+       '8': true, '9': true,
+
+       'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true, 'g': true, 'h': true,
+       'i': true, 'j': true, 'k': true, 'l': true, 'm': true, 'n': true, 'o': true, 'p': true,
+       'q': true, 'r': true, 's': true, 't': true, 'u': true, 'v': true, 'w': true, 'x': true,
+       'y': true, 'z': true,
+
+       'A': true, 'B': true, 'C': true, 'D': true, 'E': true, 'F': true, 'G': true, 'H': true,
+       'I': true, 'J': true, 'K': true, 'L': true, 'M': true, 'N': true, 'O': true, 'P': true,
+       'Q': true, 'R': true, 'S': true, 'T': true, 'U': true, 'V': true, 'W': true, 'X': true,
+       'Y': true, 'Z': true,
+
+       '!':  true, // sub-delims
+       '$':  true, // sub-delims
+       '%':  true, // pct-encoded (and used in IPv6 zones)
+       '&':  true, // sub-delims
+       '(':  true, // sub-delims
+       ')':  true, // sub-delims
+       '*':  true, // sub-delims
+       '+':  true, // sub-delims
+       ',':  true, // sub-delims
+       '-':  true, // unreserved
+       '.':  true, // unreserved
+       ':':  true, // IPv6address + Host expression's optional port
+       ';':  true, // sub-delims
+       '=':  true, // sub-delims
+       '[':  true,
+       '\'': true, // sub-delims
+       ']':  true,
+       '_':  true, // unreserved
+       '~':  true, // unreserved
+}
+
+func validHeaderName(v string) bool {
+       if len(v) == 0 {
+               return false
+       }
+       return strings.IndexFunc(v, isNotToken) == -1
+}
+
+// validHeaderValue reports whether v is a valid "field-value" according to
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 :
+//
+//        message-header = field-name ":" [ field-value ]
+//        field-value    = *( field-content | LWS )
+//        field-content  = <the OCTETs making up the field-value
+//                         and consisting of either *TEXT or combinations
+//                         of token, separators, and quoted-string>
+//
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 :
+//
+//        TEXT           = <any OCTET except CTLs,
+//                          but including LWS>
+//        LWS            = [CRLF] 1*( SP | HT )
+//        CTL            = <any US-ASCII control character
+//                         (octets 0 - 31) and DEL (127)>
+func validHeaderValue(v string) bool {
+       for i := 0; i < len(v); i++ {
+               b := v[i]
+               if isCTL(b) && !isLWS(b) {
+                       return false
+               }
+       }
+       return true
+}
index 627620c0c41e5532381b65c35a7cfbba4a9b3fe8..0ecdf85a5639a0bac57dbc8f433c8474024d8589 100644 (file)
@@ -13,7 +13,6 @@ import (
        "io/ioutil"
        "mime/multipart"
        . "net/http"
-       "net/http/httptest"
        "net/url"
        "os"
        "reflect"
@@ -177,9 +176,11 @@ func TestParseMultipartForm(t *testing.T) {
        }
 }
 
-func TestRedirect(t *testing.T) {
+func TestRedirect_h1(t *testing.T) { testRedirect(t, h1Mode) }
+func TestRedirect_h2(t *testing.T) { testRedirect(t, h2Mode) }
+func testRedirect(t *testing.T, h2 bool) {
        defer afterTest(t)
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
                switch r.URL.Path {
                case "/":
                        w.Header().Set("Location", "/foo/")
@@ -190,10 +191,10 @@ func TestRedirect(t *testing.T) {
                        w.WriteHeader(StatusBadRequest)
                }
        }))
-       defer ts.Close()
+       defer cst.close()
 
        var end = regexp.MustCompile("/foo/$")
-       r, err := Get(ts.URL)
+       r, err := cst.c.Get(cst.ts.URL)
        if err != nil {
                t.Fatal(err)
        }
@@ -355,6 +356,29 @@ func TestNewRequestHost(t *testing.T) {
        }
 }
 
+func TestRequestInvalidMethod(t *testing.T) {
+       _, err := NewRequest("bad method", "http://foo.com/", nil)
+       if err == nil {
+               t.Error("expected error from NewRequest with invalid method")
+       }
+       req, err := NewRequest("GET", "http://foo.example/", nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+       req.Method = "bad method"
+       _, err = DefaultClient.Do(req)
+       if err == nil || !strings.Contains(err.Error(), "invalid method") {
+               t.Errorf("Transport error = %v; want invalid method", err)
+       }
+
+       req, err = NewRequest("", "http://foo.com/", nil)
+       if err != nil {
+               t.Errorf("NewRequest(empty method) = %v; want nil", err)
+       } else if req.Method != "GET" {
+               t.Errorf("NewRequest(empty method) has method %q; want GET", req.Method)
+       }
+}
+
 func TestNewRequestContentLength(t *testing.T) {
        readByte := func(r io.Reader) io.Reader {
                var b [1]byte
@@ -515,10 +539,12 @@ func TestRequestWriteBufferedWriter(t *testing.T) {
 
 func TestRequestBadHost(t *testing.T) {
        got := []string{}
-       req, err := NewRequest("GET", "http://foo.com with spaces/after", nil)
+       req, err := NewRequest("GET", "http://foo/after", nil)
        if err != nil {
                t.Fatal(err)
        }
+       req.Host = "foo.com with spaces"
+       req.URL.Host = "foo.com with spaces"
        req.Write(logWrites{t, &got})
        want := []string{
                "GET /after HTTP/1.1\r\n",
index 76b8538524476560e282a172d87ffb7ebfd61f5b..c424f61cd00e19ba8d6e7b98aa806302eb8af050 100644 (file)
@@ -72,8 +72,18 @@ type Response struct {
        // ReadResponse nor Response.Write ever closes a connection.
        Close bool
 
-       // Trailer maps trailer keys to values, in the same
-       // format as the header.
+       // Trailer maps trailer keys to values in the same
+       // format as Header.
+       //
+       // The Trailer initially contains only nil values, one for
+       // each key specified in the server's "Trailer" header
+       // value. Those values are not added to Header.
+       //
+       // Trailer must not be accessed concurrently with Read calls
+       // on the Body.
+       //
+       // After Body.Read has returned io.EOF, Trailer will contain
+       // any trailer values sent by the server.
        Trailer Header
 
        // The Request that was sent to obtain this Response.
@@ -140,12 +150,14 @@ func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) {
        if len(f) > 2 {
                reasonPhrase = f[2]
        }
-       resp.Status = f[1] + " " + reasonPhrase
+       if len(f[1]) != 3 {
+               return nil, &badStringError{"malformed HTTP status code", f[1]}
+       }
        resp.StatusCode, err = strconv.Atoi(f[1])
-       if err != nil {
+       if err != nil || resp.StatusCode < 0 {
                return nil, &badStringError{"malformed HTTP status code", f[1]}
        }
-
+       resp.Status = f[1] + " " + reasonPhrase
        resp.Proto = f[0]
        var ok bool
        if resp.ProtoMajor, resp.ProtoMinor, ok = ParseHTTPVersion(resp.Proto); !ok {
index 421cf55f49173813c4ceedc5dd45d45696c26167..d8a53400cf23d654813d9530466109a0dfb41e0f 100644 (file)
@@ -456,8 +456,59 @@ some body`,
 
                "",
        },
+
+       // Issue 12785: HTTP/1.0 response with bogus (to be ignored) Transfer-Encoding.
+       // Without a Content-Length.
+       {
+               "HTTP/1.0 200 OK\r\n" +
+                       "Transfer-Encoding: bogus\r\n" +
+                       "\r\n" +
+                       "Body here\n",
+
+               Response{
+                       Status:        "200 OK",
+                       StatusCode:    200,
+                       Proto:         "HTTP/1.0",
+                       ProtoMajor:    1,
+                       ProtoMinor:    0,
+                       Request:       dummyReq("GET"),
+                       Header:        Header{},
+                       Close:         true,
+                       ContentLength: -1,
+               },
+
+               "Body here\n",
+       },
+
+       // Issue 12785: HTTP/1.0 response with bogus (to be ignored) Transfer-Encoding.
+       // With a Content-Length.
+       {
+               "HTTP/1.0 200 OK\r\n" +
+                       "Transfer-Encoding: bogus\r\n" +
+                       "Content-Length: 10\r\n" +
+                       "\r\n" +
+                       "Body here\n",
+
+               Response{
+                       Status:     "200 OK",
+                       StatusCode: 200,
+                       Proto:      "HTTP/1.0",
+                       ProtoMajor: 1,
+                       ProtoMinor: 0,
+                       Request:    dummyReq("GET"),
+                       Header: Header{
+                               "Content-Length": {"10"},
+                       },
+                       Close:         true,
+                       ContentLength: 10,
+               },
+
+               "Body here\n",
+       },
 }
 
+// tests successful calls to ReadResponse, and inspects the returned Response.
+// For error cases, see TestReadResponseErrors below.
 func TestReadResponse(t *testing.T) {
        for i, tt := range respTests {
                resp, err := ReadResponse(bufio.NewReader(strings.NewReader(tt.Raw)), tt.Resp.Request)
@@ -624,6 +675,7 @@ var responseLocationTests = []responseLocationTest{
        {"/foo", "http://bar.com/baz", "http://bar.com/foo", nil},
        {"http://foo.com/", "http://bar.com/baz", "http://foo.com/", nil},
        {"", "http://bar.com/baz", "", ErrNoLocation},
+       {"/bar", "", "/bar", nil},
 }
 
 func TestLocationResponse(t *testing.T) {
@@ -702,13 +754,106 @@ func TestResponseContentLengthShortBody(t *testing.T) {
        }
 }
 
-func TestReadResponseUnexpectedEOF(t *testing.T) {
-       br := bufio.NewReader(strings.NewReader("HTTP/1.1 301 Moved Permanently\r\n" +
-               "Location: http://example.com"))
-       _, err := ReadResponse(br, nil)
-       if err != io.ErrUnexpectedEOF {
-               t.Errorf("ReadResponse = %v; want io.ErrUnexpectedEOF", err)
+// Test various ReadResponse error cases. (also tests success cases, but mostly
+// it's about errors).  This does not test anything involving the bodies. Only
+// the return value from ReadResponse itself.
+func TestReadResponseErrors(t *testing.T) {
+       type testCase struct {
+               name    string // optional, defaults to in
+               in      string
+               wantErr interface{} // nil, err value, or string substring
+       }
+
+       status := func(s string, wantErr interface{}) testCase {
+               if wantErr == true {
+                       wantErr = "malformed HTTP status code"
+               }
+               return testCase{
+                       name:    fmt.Sprintf("status %q", s),
+                       in:      "HTTP/1.1 " + s + "\r\nFoo: bar\r\n\r\n",
+                       wantErr: wantErr,
+               }
+       }
+
+       version := func(s string, wantErr interface{}) testCase {
+               if wantErr == true {
+                       wantErr = "malformed HTTP version"
+               }
+               return testCase{
+                       name:    fmt.Sprintf("version %q", s),
+                       in:      s + " 200 OK\r\n\r\n",
+                       wantErr: wantErr,
+               }
+       }
+
+       tests := []testCase{
+               {"", "", io.ErrUnexpectedEOF},
+               {"", "HTTP/1.1 301 Moved Permanently\r\nFoo: bar", io.ErrUnexpectedEOF},
+               {"", "HTTP/1.1", "malformed HTTP response"},
+               {"", "HTTP/2.0", "malformed HTTP response"},
+               status("20X Unknown", true),
+               status("abcd Unknown", true),
+               status("二百/两百 OK", true),
+               status(" Unknown", true),
+               status("c8 OK", true),
+               status("0x12d Moved Permanently", true),
+               status("200 OK", nil),
+               status("000 OK", nil),
+               status("001 OK", nil),
+               status("404 NOTFOUND", nil),
+               status("20 OK", true),
+               status("00 OK", true),
+               status("-10 OK", true),
+               status("1000 OK", true),
+               status("999 Done", nil),
+               status("-1 OK", true),
+               status("-200 OK", true),
+               version("HTTP/1.2", nil),
+               version("HTTP/2.0", nil),
+               version("HTTP/1.100000000002", true),
+               version("HTTP/1.-1", true),
+               version("HTTP/A.B", true),
+               version("HTTP/1", true),
+               version("http/1.1", true),
+       }
+       for i, tt := range tests {
+               br := bufio.NewReader(strings.NewReader(tt.in))
+               _, rerr := ReadResponse(br, nil)
+               if err := matchErr(rerr, tt.wantErr); err != nil {
+                       name := tt.name
+                       if name == "" {
+                               name = fmt.Sprintf("%d. input %q", i, tt.in)
+                       }
+                       t.Errorf("%s: %v", name, err)
+               }
+       }
+}
+
+// wantErr can be nil, an error value to match exactly, or type string to
+// match a substring.
+func matchErr(err error, wantErr interface{}) error {
+       if err == nil {
+               if wantErr == nil {
+                       return nil
+               }
+               if sub, ok := wantErr.(string); ok {
+                       return fmt.Errorf("unexpected success; want error with substring %q", sub)
+               }
+               return fmt.Errorf("unexpected success; want error %v", wantErr)
+       }
+       if wantErr == nil {
+               return fmt.Errorf("%v; want success", err)
+       }
+       if sub, ok := wantErr.(string); ok {
+               if strings.Contains(err.Error(), sub) {
+                       return nil
+               }
+               return fmt.Errorf("error = %v; want an error with substring %q", err, sub)
+       }
+       if err == wantErr {
+               return nil
        }
+       return fmt.Errorf("%v; want %v", err, wantErr)
 }
 
 func TestNeedsSniff(t *testing.T) {
index d51417eb4a0708068c5323590c74add2add830f5..f8cad802d4986a9293c533284c6ca59bc99a342c 100644 (file)
@@ -12,6 +12,7 @@ import (
        "crypto/tls"
        "errors"
        "fmt"
+       "internal/testenv"
        "io"
        "io/ioutil"
        "log"
@@ -26,6 +27,8 @@ import (
        "os/exec"
        "reflect"
        "runtime"
+       "runtime/debug"
+       "sort"
        "strconv"
        "strings"
        "sync"
@@ -96,6 +99,7 @@ func (c *rwTestConn) Close() error {
 }
 
 type testConn struct {
+       readMu   sync.Mutex // for TestHandlerBodyClose
        readBuf  bytes.Buffer
        writeBuf bytes.Buffer
        closec   chan bool // if non-nil, send value to it on close
@@ -103,6 +107,8 @@ type testConn struct {
 }
 
 func (c *testConn) Read(b []byte) (int, error) {
+       c.readMu.Lock()
+       defer c.readMu.Unlock()
        return c.readBuf.Read(b)
 }
 
@@ -450,6 +456,7 @@ func TestServerTimeouts(t *testing.T) {
        if runtime.GOOS == "plan9" {
                t.Skip("skipping test; see https://golang.org/issue/7237")
        }
+       setParallel(t)
        defer afterTest(t)
        reqNum := 0
        ts := httptest.NewUnstartedServer(HandlerFunc(func(res ResponseWriter, req *Request) {
@@ -734,14 +741,17 @@ func TestHandlersCanSetConnectionClose10(t *testing.T) {
        }))
 }
 
-func TestSetsRemoteAddr(t *testing.T) {
+func TestSetsRemoteAddr_h1(t *testing.T) { testSetsRemoteAddr(t, h1Mode) }
+func TestSetsRemoteAddr_h2(t *testing.T) { testSetsRemoteAddr(t, h2Mode) }
+
+func testSetsRemoteAddr(t *testing.T, h2 bool) {
        defer afterTest(t)
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
                fmt.Fprintf(w, "%s", r.RemoteAddr)
        }))
-       defer ts.Close()
+       defer cst.close()
 
-       res, err := Get(ts.URL)
+       res, err := cst.c.Get(cst.ts.URL)
        if err != nil {
                t.Fatalf("Get error: %v", err)
        }
@@ -755,34 +765,106 @@ func TestSetsRemoteAddr(t *testing.T) {
        }
 }
 
-func TestChunkedResponseHeaders(t *testing.T) {
-       defer afterTest(t)
-       log.SetOutput(ioutil.Discard) // is noisy otherwise
-       defer log.SetOutput(os.Stderr)
+type blockingRemoteAddrListener struct {
+       net.Listener
+       conns chan<- net.Conn
+}
 
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-               w.Header().Set("Content-Length", "intentional gibberish") // we check that this is deleted
-               w.(Flusher).Flush()
-               fmt.Fprintf(w, "I am a chunked response.")
+func (l *blockingRemoteAddrListener) Accept() (net.Conn, error) {
+       c, err := l.Listener.Accept()
+       if err != nil {
+               return nil, err
+       }
+       brac := &blockingRemoteAddrConn{
+               Conn:  c,
+               addrs: make(chan net.Addr, 1),
+       }
+       l.conns <- brac
+       return brac, nil
+}
+
+type blockingRemoteAddrConn struct {
+       net.Conn
+       addrs chan net.Addr
+}
+
+func (c *blockingRemoteAddrConn) RemoteAddr() net.Addr {
+       return <-c.addrs
+}
+
+// Issue 12943
+func TestServerAllowsBlockingRemoteAddr(t *testing.T) {
+       defer afterTest(t)
+       ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+               fmt.Fprintf(w, "RA:%s", r.RemoteAddr)
        }))
+       conns := make(chan net.Conn)
+       ts.Listener = &blockingRemoteAddrListener{
+               Listener: ts.Listener,
+               conns:    conns,
+       }
+       ts.Start()
        defer ts.Close()
 
-       res, err := Get(ts.URL)
-       if err != nil {
-               t.Fatalf("Get error: %v", err)
+       tr := &Transport{DisableKeepAlives: true}
+       defer tr.CloseIdleConnections()
+       c := &Client{Transport: tr, Timeout: time.Second}
+
+       fetch := func(response chan string) {
+               resp, err := c.Get(ts.URL)
+               if err != nil {
+                       t.Error(err)
+                       response <- ""
+                       return
+               }
+               defer resp.Body.Close()
+               body, err := ioutil.ReadAll(resp.Body)
+               if err != nil {
+                       t.Error(err)
+                       response <- ""
+                       return
+               }
+               response <- string(body)
        }
-       defer res.Body.Close()
-       if g, e := res.ContentLength, int64(-1); g != e {
-               t.Errorf("expected ContentLength of %d; got %d", e, g)
+
+       // Start a request. The server will block on getting conn.RemoteAddr.
+       response1c := make(chan string, 1)
+       go fetch(response1c)
+
+       // Wait for the server to accept it; grab the connection.
+       conn1 := <-conns
+
+       // Start another request and grab its connection
+       response2c := make(chan string, 1)
+       go fetch(response2c)
+       var conn2 net.Conn
+
+       select {
+       case conn2 = <-conns:
+       case <-time.After(time.Second):
+               t.Fatal("Second Accept didn't happen")
        }
-       if g, e := res.TransferEncoding, []string{"chunked"}; !reflect.DeepEqual(g, e) {
-               t.Errorf("expected TransferEncoding of %v; got %v", e, g)
+
+       // Send a response on connection 2.
+       conn2.(*blockingRemoteAddrConn).addrs <- &net.TCPAddr{
+               IP: net.ParseIP("12.12.12.12"), Port: 12}
+
+       // ... and see it
+       response2 := <-response2c
+       if g, e := response2, "RA:12.12.12.12:12"; g != e {
+               t.Fatalf("response 2 addr = %q; want %q", g, e)
        }
-       if _, haveCL := res.Header["Content-Length"]; haveCL {
-               t.Errorf("Unexpected Content-Length")
+
+       // Finish the first response.
+       conn1.(*blockingRemoteAddrConn).addrs <- &net.TCPAddr{
+               IP: net.ParseIP("21.21.21.21"), Port: 21}
+
+       // ... and see it
+       response1 := <-response1c
+       if g, e := response1, "RA:21.21.21.21:21"; g != e {
+               t.Fatalf("response 1 addr = %q; want %q", g, e)
        }
 }
-
 func TestIdentityResponseHeaders(t *testing.T) {
        defer afterTest(t)
        log.SetOutput(ioutil.Discard) // is noisy otherwise
@@ -812,40 +894,14 @@ func TestIdentityResponseHeaders(t *testing.T) {
        }
 }
 
-// Test304Responses verifies that 304s don't declare that they're
-// chunking in their response headers and aren't allowed to produce
-// output.
-func Test304Responses(t *testing.T) {
-       defer afterTest(t)
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-               w.WriteHeader(StatusNotModified)
-               _, err := w.Write([]byte("illegal body"))
-               if err != ErrBodyNotAllowed {
-                       t.Errorf("on Write, expected ErrBodyNotAllowed, got %v", err)
-               }
-       }))
-       defer ts.Close()
-       res, err := Get(ts.URL)
-       if err != nil {
-               t.Error(err)
-       }
-       if len(res.TransferEncoding) > 0 {
-               t.Errorf("expected no TransferEncoding; got %v", res.TransferEncoding)
-       }
-       body, err := ioutil.ReadAll(res.Body)
-       if err != nil {
-               t.Error(err)
-       }
-       if len(body) > 0 {
-               t.Errorf("got unexpected body %q", string(body))
-       }
-}
-
 // TestHeadResponses verifies that all MIME type sniffing and Content-Length
 // counting of GET requests also happens on HEAD requests.
-func TestHeadResponses(t *testing.T) {
+func TestHeadResponses_h1(t *testing.T) { testHeadResponses(t, h1Mode) }
+func TestHeadResponses_h2(t *testing.T) { testHeadResponses(t, h2Mode) }
+
+func testHeadResponses(t *testing.T, h2 bool) {
        defer afterTest(t)
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
                _, err := w.Write([]byte("<html>"))
                if err != nil {
                        t.Errorf("ResponseWriter.Write: %v", err)
@@ -857,8 +913,8 @@ func TestHeadResponses(t *testing.T) {
                        t.Errorf("Copy(ResponseWriter, ...): %v", err)
                }
        }))
-       defer ts.Close()
-       res, err := Head(ts.URL)
+       defer cst.close()
+       res, err := cst.c.Head(cst.ts.URL)
        if err != nil {
                t.Error(err)
        }
@@ -884,6 +940,7 @@ func TestTLSHandshakeTimeout(t *testing.T) {
        if runtime.GOOS == "plan9" {
                t.Skip("skipping test; see https://golang.org/issue/7237")
        }
+       setParallel(t)
        defer afterTest(t)
        ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
        errc := make(chanWriter, 10) // but only expecting 1
@@ -967,6 +1024,79 @@ func TestTLSServer(t *testing.T) {
        })
 }
 
+func TestAutomaticHTTP2_Serve(t *testing.T) {
+       defer afterTest(t)
+       ln := newLocalListener(t)
+       ln.Close() // immediately (not a defer!)
+       var s Server
+       if err := s.Serve(ln); err == nil {
+               t.Fatal("expected an error")
+       }
+       on := s.TLSNextProto["h2"] != nil
+       if !on {
+               t.Errorf("http2 wasn't automatically enabled")
+       }
+}
+
+func TestAutomaticHTTP2_ListenAndServe(t *testing.T) {
+       defer afterTest(t)
+       defer SetTestHookServerServe(nil)
+       cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey)
+       if err != nil {
+               t.Fatal(err)
+       }
+       var ok bool
+       var s *Server
+       const maxTries = 5
+       var ln net.Listener
+Try:
+       for try := 0; try < maxTries; try++ {
+               ln = newLocalListener(t)
+               addr := ln.Addr().String()
+               ln.Close()
+               t.Logf("Got %v", addr)
+               lnc := make(chan net.Listener, 1)
+               SetTestHookServerServe(func(s *Server, ln net.Listener) {
+                       lnc <- ln
+               })
+               s = &Server{
+                       Addr: addr,
+                       TLSConfig: &tls.Config{
+                               Certificates: []tls.Certificate{cert},
+                       },
+               }
+               errc := make(chan error, 1)
+               go func() { errc <- s.ListenAndServeTLS("", "") }()
+               select {
+               case err := <-errc:
+                       t.Logf("On try #%v: %v", try+1, err)
+                       continue
+               case ln = <-lnc:
+                       ok = true
+                       t.Logf("Listening on %v", ln.Addr().String())
+                       break Try
+               }
+       }
+       if !ok {
+               t.Fatalf("Failed to start up after %d tries", maxTries)
+       }
+       defer ln.Close()
+       c, err := tls.Dial("tcp", ln.Addr().String(), &tls.Config{
+               InsecureSkipVerify: true,
+               NextProtos:         []string{"h2", "http/1.1"},
+       })
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer c.Close()
+       if got, want := c.ConnectionState().NegotiatedProtocol, "h2"; got != want {
+               t.Errorf("NegotiatedProtocol = %q; want %q", got, want)
+       }
+       if got, want := c.ConnectionState().NegotiatedProtocolIsMutual, true; got != want {
+               t.Errorf("NegotiatedProtocolIsMutual = %v; want %v", got, want)
+       }
+}
+
 type serverExpectTest struct {
        contentLength    int // of request body
        chunked          bool
@@ -1016,6 +1146,7 @@ var serverExpectTests = []serverExpectTest{
 
 // Tests that the server responds to the "Expect" request header
 // correctly.
+// http2 test: TestServer_Response_Automatic100Continue
 func TestServerExpect(t *testing.T) {
        defer afterTest(t)
        ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -1122,15 +1253,21 @@ func TestServerUnreadRequestBodyLittle(t *testing.T) {
 
        done := make(chan bool)
 
+       readBufLen := func() int {
+               conn.readMu.Lock()
+               defer conn.readMu.Unlock()
+               return conn.readBuf.Len()
+       }
+
        ls := &oneConnListener{conn}
        go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) {
                defer close(done)
-               if conn.readBuf.Len() < len(body)/2 {
-                       t.Errorf("on request, read buffer length is %d; expected about 100 KB", conn.readBuf.Len())
+               if bufLen := readBufLen(); bufLen < len(body)/2 {
+                       t.Errorf("on request, read buffer length is %d; expected about 100 KB", bufLen)
                }
                rw.WriteHeader(200)
                rw.(Flusher).Flush()
-               if g, e := conn.readBuf.Len(), 0; g != e {
+               if g, e := readBufLen(), 0; g != e {
                        t.Errorf("after WriteHeader, read buffer length is %d; want %d", g, e)
                }
                if c := rw.Header().Get("Connection"); c != "" {
@@ -1144,6 +1281,9 @@ func TestServerUnreadRequestBodyLittle(t *testing.T) {
 // should ignore client request bodies that a handler didn't read
 // and close the connection.
 func TestServerUnreadRequestBodyLarge(t *testing.T) {
+       if testing.Short() && testenv.Builder() == "" {
+               t.Log("skipping in short mode")
+       }
        conn := new(testConn)
        body := strings.Repeat("x", 1<<20)
        conn.readBuf.Write([]byte(fmt.Sprintf(
@@ -1274,6 +1414,9 @@ var handlerBodyCloseTests = [...]handlerBodyCloseTest{
 }
 
 func TestHandlerBodyClose(t *testing.T) {
+       if testing.Short() && testenv.Builder() == "" {
+               t.Skip("skipping in -short mode")
+       }
        for i, tt := range handlerBodyCloseTests {
                testHandlerBodyClose(t, i, tt)
        }
@@ -1306,15 +1449,21 @@ func testHandlerBodyClose(t *testing.T, i int, tt handlerBodyCloseTest) {
        }
        conn.closec = make(chan bool, 1)
 
+       readBufLen := func() int {
+               conn.readMu.Lock()
+               defer conn.readMu.Unlock()
+               return conn.readBuf.Len()
+       }
+
        ls := &oneConnListener{conn}
        var numReqs int
        var size0, size1 int
        go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) {
                numReqs++
                if numReqs == 1 {
-                       size0 = conn.readBuf.Len()
+                       size0 = readBufLen()
                        req.Body.Close()
-                       size1 = conn.readBuf.Len()
+                       size1 = readBufLen()
                }
        }))
        <-conn.closec
@@ -1414,7 +1563,9 @@ type slowTestConn struct {
        // over multiple calls to Read, time.Durations are slept, strings are read.
        script []interface{}
        closec chan bool
-       rd, wd time.Time // read, write deadline
+
+       mu     sync.Mutex // guards rd/wd
+       rd, wd time.Time  // read, write deadline
        noopConn
 }
 
@@ -1425,16 +1576,22 @@ func (c *slowTestConn) SetDeadline(t time.Time) error {
 }
 
 func (c *slowTestConn) SetReadDeadline(t time.Time) error {
+       c.mu.Lock()
+       defer c.mu.Unlock()
        c.rd = t
        return nil
 }
 
 func (c *slowTestConn) SetWriteDeadline(t time.Time) error {
+       c.mu.Lock()
+       defer c.mu.Unlock()
        c.wd = t
        return nil
 }
 
 func (c *slowTestConn) Read(b []byte) (n int, err error) {
+       c.mu.Lock()
+       defer c.mu.Unlock()
 restart:
        if !c.rd.IsZero() && time.Now().After(c.rd) {
                return 0, syscall.ETIMEDOUT
@@ -1531,7 +1688,9 @@ func TestRequestBodyTimeoutClosesConnection(t *testing.T) {
        }
 }
 
-func TestTimeoutHandler(t *testing.T) {
+func TestTimeoutHandler_h1(t *testing.T) { testTimeoutHandler(t, h1Mode) }
+func TestTimeoutHandler_h2(t *testing.T) { testTimeoutHandler(t, h2Mode) }
+func testTimeoutHandler(t *testing.T, h2 bool) {
        defer afterTest(t)
        sendHi := make(chan bool, 1)
        writeErrors := make(chan error, 1)
@@ -1541,12 +1700,12 @@ func TestTimeoutHandler(t *testing.T) {
                writeErrors <- werr
        })
        timeout := make(chan time.Time, 1) // write to this to force timeouts
-       ts := httptest.NewServer(NewTestTimeoutHandler(sayHi, timeout))
-       defer ts.Close()
+       cst := newClientServerTest(t, h2, NewTestTimeoutHandler(sayHi, timeout))
+       defer cst.close()
 
        // Succeed without timing out:
        sendHi <- true
-       res, err := Get(ts.URL)
+       res, err := cst.c.Get(cst.ts.URL)
        if err != nil {
                t.Error(err)
        }
@@ -1563,7 +1722,7 @@ func TestTimeoutHandler(t *testing.T) {
 
        // Times out:
        timeout <- time.Time{}
-       res, err = Get(ts.URL)
+       res, err = cst.c.Get(cst.ts.URL)
        if err != nil {
                t.Error(err)
        }
@@ -1659,6 +1818,60 @@ func TestTimeoutHandlerRaceHeader(t *testing.T) {
        wg.Wait()
 }
 
+// Issue 9162
+func TestTimeoutHandlerRaceHeaderTimeout(t *testing.T) {
+       defer afterTest(t)
+       sendHi := make(chan bool, 1)
+       writeErrors := make(chan error, 1)
+       sayHi := HandlerFunc(func(w ResponseWriter, r *Request) {
+               w.Header().Set("Content-Type", "text/plain")
+               <-sendHi
+               _, werr := w.Write([]byte("hi"))
+               writeErrors <- werr
+       })
+       timeout := make(chan time.Time, 1) // write to this to force timeouts
+       cst := newClientServerTest(t, h1Mode, NewTestTimeoutHandler(sayHi, timeout))
+       defer cst.close()
+
+       // Succeed without timing out:
+       sendHi <- true
+       res, err := cst.c.Get(cst.ts.URL)
+       if err != nil {
+               t.Error(err)
+       }
+       if g, e := res.StatusCode, StatusOK; g != e {
+               t.Errorf("got res.StatusCode %d; expected %d", g, e)
+       }
+       body, _ := ioutil.ReadAll(res.Body)
+       if g, e := string(body), "hi"; g != e {
+               t.Errorf("got body %q; expected %q", g, e)
+       }
+       if g := <-writeErrors; g != nil {
+               t.Errorf("got unexpected Write error on first request: %v", g)
+       }
+
+       // Times out:
+       timeout <- time.Time{}
+       res, err = cst.c.Get(cst.ts.URL)
+       if err != nil {
+               t.Error(err)
+       }
+       if g, e := res.StatusCode, StatusServiceUnavailable; g != e {
+               t.Errorf("got res.StatusCode %d; expected %d", g, e)
+       }
+       body, _ = ioutil.ReadAll(res.Body)
+       if !strings.Contains(string(body), "<title>Timeout</title>") {
+               t.Errorf("expected timeout body; got %q", string(body))
+       }
+
+       // Now make the previously-timed out handler speak again,
+       // which verifies the panic is handled:
+       sendHi <- true
+       if g, e := <-writeErrors, ErrHandlerTimeout; g != e {
+               t.Errorf("expected Write error of %v; got %v", e, g)
+       }
+}
+
 // Verifies we don't path.Clean() on the wrong parts in redirects.
 func TestRedirectMunging(t *testing.T) {
        req, _ := NewRequest("GET", "http://example.com/", nil)
@@ -1693,15 +1906,57 @@ func TestRedirectBadPath(t *testing.T) {
        }
 }
 
+// Test different URL formats and schemes
+func TestRedirectURLFormat(t *testing.T) {
+       req, _ := NewRequest("GET", "http://example.com/qux/", nil)
+
+       var tests = []struct {
+               in   string
+               want string
+       }{
+               // normal http
+               {"http://foobar.com/baz", "http://foobar.com/baz"},
+               // normal https
+               {"https://foobar.com/baz", "https://foobar.com/baz"},
+               // custom scheme
+               {"test://foobar.com/baz", "test://foobar.com/baz"},
+               // schemeless
+               {"//foobar.com/baz", "//foobar.com/baz"},
+               // relative to the root
+               {"/foobar.com/baz", "/foobar.com/baz"},
+               // relative to the current path
+               {"foobar.com/baz", "/qux/foobar.com/baz"},
+               // relative to the current path (+ going upwards)
+               {"../quux/foobar.com/baz", "/quux/foobar.com/baz"},
+               // incorrect number of slashes
+               {"///foobar.com/baz", "/foobar.com/baz"},
+       }
+
+       for _, tt := range tests {
+               rec := httptest.NewRecorder()
+               Redirect(rec, req, tt.in, 302)
+               if got := rec.Header().Get("Location"); got != tt.want {
+                       t.Errorf("Redirect(%q) generated Location header %q; want %q", tt.in, got, tt.want)
+               }
+       }
+}
+
 // TestZeroLengthPostAndResponse exercises an optimization done by the Transport:
 // when there is no body (either because the method doesn't permit a body, or an
 // explicit Content-Length of zero is present), then the transport can re-use the
 // connection immediately. But when it re-uses the connection, it typically closes
 // the previous request's body, which is not optimal for zero-lengthed bodies,
 // as the client would then see http.ErrBodyReadAfterClose and not 0, io.EOF.
-func TestZeroLengthPostAndResponse(t *testing.T) {
+func TestZeroLengthPostAndResponse_h1(t *testing.T) {
+       testZeroLengthPostAndResponse(t, h1Mode)
+}
+func TestZeroLengthPostAndResponse_h2(t *testing.T) {
+       testZeroLengthPostAndResponse(t, h2Mode)
+}
+
+func testZeroLengthPostAndResponse(t *testing.T, h2 bool) {
        defer afterTest(t)
-       ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(rw ResponseWriter, r *Request) {
                all, err := ioutil.ReadAll(r.Body)
                if err != nil {
                        t.Fatalf("handler ReadAll: %v", err)
@@ -1711,9 +1966,9 @@ func TestZeroLengthPostAndResponse(t *testing.T) {
                }
                rw.Header().Set("Content-Length", "0")
        }))
-       defer ts.Close()
+       defer cst.close()
 
-       req, err := NewRequest("POST", ts.URL, strings.NewReader(""))
+       req, err := NewRequest("POST", cst.ts.URL, strings.NewReader(""))
        if err != nil {
                t.Fatal(err)
        }
@@ -1721,7 +1976,7 @@ func TestZeroLengthPostAndResponse(t *testing.T) {
 
        var resp [5]*Response
        for i := range resp {
-               resp[i], err = DefaultClient.Do(req)
+               resp[i], err = cst.c.Do(req)
                if err != nil {
                        t.Fatalf("client post #%d: %v", i, err)
                }
@@ -1738,19 +1993,22 @@ func TestZeroLengthPostAndResponse(t *testing.T) {
        }
 }
 
-func TestHandlerPanicNil(t *testing.T) {
-       testHandlerPanic(t, false, nil)
-}
+func TestHandlerPanicNil_h1(t *testing.T) { testHandlerPanic(t, false, h1Mode, nil) }
+func TestHandlerPanicNil_h2(t *testing.T) { testHandlerPanic(t, false, h2Mode, nil) }
 
-func TestHandlerPanic(t *testing.T) {
-       testHandlerPanic(t, false, "intentional death for testing")
+func TestHandlerPanic_h1(t *testing.T) {
+       testHandlerPanic(t, false, h1Mode, "intentional death for testing")
+}
+func TestHandlerPanic_h2(t *testing.T) {
+       testHandlerPanic(t, false, h2Mode, "intentional death for testing")
 }
 
 func TestHandlerPanicWithHijack(t *testing.T) {
-       testHandlerPanic(t, true, "intentional death for testing")
+       // Only testing HTTP/1, and our http2 server doesn't support hijacking.
+       testHandlerPanic(t, true, h1Mode, "intentional death for testing")
 }
 
-func testHandlerPanic(t *testing.T, withHijack bool, panicValue interface{}) {
+func testHandlerPanic(t *testing.T, withHijack, h2 bool, panicValue interface{}) {
        defer afterTest(t)
        // Unlike the other tests that set the log output to ioutil.Discard
        // to quiet the output, this test uses a pipe.  The pipe serves three
@@ -1773,7 +2031,7 @@ func testHandlerPanic(t *testing.T, withHijack bool, panicValue interface{}) {
        defer log.SetOutput(os.Stderr)
        defer pw.Close()
 
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
                if withHijack {
                        rwc, _, err := w.(Hijacker).Hijack()
                        if err != nil {
@@ -1783,7 +2041,7 @@ func testHandlerPanic(t *testing.T, withHijack bool, panicValue interface{}) {
                }
                panic(panicValue)
        }))
-       defer ts.Close()
+       defer cst.close()
 
        // Do a blocking read on the log output pipe so its logging
        // doesn't bleed into the next test.  But wait only 5 seconds
@@ -1799,7 +2057,7 @@ func testHandlerPanic(t *testing.T, withHijack bool, panicValue interface{}) {
                done <- true
        }()
 
-       _, err := Get(ts.URL)
+       _, err := cst.c.Get(cst.ts.URL)
        if err == nil {
                t.Logf("expected an error")
        }
@@ -1816,17 +2074,19 @@ func testHandlerPanic(t *testing.T, withHijack bool, panicValue interface{}) {
        }
 }
 
-func TestServerNoDate(t *testing.T)        { testServerNoHeader(t, "Date") }
-func TestServerNoContentType(t *testing.T) { testServerNoHeader(t, "Content-Type") }
+func TestServerNoDate_h1(t *testing.T)        { testServerNoHeader(t, h1Mode, "Date") }
+func TestServerNoDate_h2(t *testing.T)        { testServerNoHeader(t, h2Mode, "Date") }
+func TestServerNoContentType_h1(t *testing.T) { testServerNoHeader(t, h1Mode, "Content-Type") }
+func TestServerNoContentType_h2(t *testing.T) { testServerNoHeader(t, h2Mode, "Content-Type") }
 
-func testServerNoHeader(t *testing.T, header string) {
+func testServerNoHeader(t *testing.T, h2 bool, header string) {
        defer afterTest(t)
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
                w.Header()[header] = nil
                io.WriteString(w, "<html>foo</html>") // non-empty
        }))
-       defer ts.Close()
-       res, err := Get(ts.URL)
+       defer cst.close()
+       res, err := cst.c.Get(cst.ts.URL)
        if err != nil {
                t.Fatal(err)
        }
@@ -1863,18 +2123,20 @@ func TestStripPrefix(t *testing.T) {
        res.Body.Close()
 }
 
-func TestRequestLimit(t *testing.T) {
+func TestRequestLimit_h1(t *testing.T) { testRequestLimit(t, h1Mode) }
+func TestRequestLimit_h2(t *testing.T) { testRequestLimit(t, h2Mode) }
+func testRequestLimit(t *testing.T, h2 bool) {
        defer afterTest(t)
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
                t.Fatalf("didn't expect to get request in Handler")
        }))
-       defer ts.Close()
-       req, _ := NewRequest("GET", ts.URL, nil)
+       defer cst.close()
+       req, _ := NewRequest("GET", cst.ts.URL, nil)
        var bytesPerHeader = len("header12345: val12345\r\n")
        for i := 0; i < ((DefaultMaxHeaderBytes+4096)/bytesPerHeader)+1; i++ {
                req.Header.Set(fmt.Sprintf("header%05d", i), fmt.Sprintf("val%05d", i))
        }
-       res, err := DefaultClient.Do(req)
+       res, err := cst.c.Do(req)
        if err != nil {
                // Some HTTP clients may fail on this undefined behavior (server replying and
                // closing the connection while the request is still being written), but
@@ -1882,8 +2144,8 @@ func TestRequestLimit(t *testing.T) {
                t.Fatalf("Do: %v", err)
        }
        defer res.Body.Close()
-       if res.StatusCode != 413 {
-               t.Fatalf("expected 413 response status; got: %d %s", res.StatusCode, res.Status)
+       if res.StatusCode != 431 {
+               t.Fatalf("expected 431 response status; got: %d %s", res.StatusCode, res.Status)
        }
 }
 
@@ -1907,10 +2169,12 @@ func (cr countReader) Read(p []byte) (n int, err error) {
        return
 }
 
-func TestRequestBodyLimit(t *testing.T) {
+func TestRequestBodyLimit_h1(t *testing.T) { testRequestBodyLimit(t, h1Mode) }
+func TestRequestBodyLimit_h2(t *testing.T) { testRequestBodyLimit(t, h2Mode) }
+func testRequestBodyLimit(t *testing.T, h2 bool) {
        defer afterTest(t)
        const limit = 1 << 20
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
                r.Body = MaxBytesReader(w, r.Body, limit)
                n, err := io.Copy(ioutil.Discard, r.Body)
                if err == nil {
@@ -1920,10 +2184,10 @@ func TestRequestBodyLimit(t *testing.T) {
                        t.Errorf("io.Copy = %d, want %d", n, limit)
                }
        }))
-       defer ts.Close()
+       defer cst.close()
 
        nWritten := new(int64)
-       req, _ := NewRequest("POST", ts.URL, io.LimitReader(countReader{neverEnding('a'), nWritten}, limit*200))
+       req, _ := NewRequest("POST", cst.ts.URL, io.LimitReader(countReader{neverEnding('a'), nWritten}, limit*200))
 
        // Send the POST, but don't care it succeeds or not.  The
        // remote side is going to reply and then close the TCP
@@ -1934,7 +2198,7 @@ func TestRequestBodyLimit(t *testing.T) {
        //
        // But that's okay, since what we're really testing is that
        // the remote side hung up on us before we wrote too much.
-       _, _ = DefaultClient.Do(req)
+       _, _ = cst.c.Do(req)
 
        if atomic.LoadInt64(nWritten) > limit*100 {
                t.Errorf("handler restricted the request body to %d bytes, but client managed to write %d",
@@ -1982,7 +2246,7 @@ func TestClientWriteShutdown(t *testing.T) {
 // buffered before chunk headers are added, not after chunk headers.
 func TestServerBufferedChunking(t *testing.T) {
        conn := new(testConn)
-       conn.readBuf.Write([]byte("GET / HTTP/1.1\r\n\r\n"))
+       conn.readBuf.Write([]byte("GET / HTTP/1.1\r\nHost: foo\r\n\r\n"))
        conn.closec = make(chan bool, 1)
        ls := &oneConnListener{conn}
        go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) {
@@ -2045,20 +2309,23 @@ func TestServerGracefulClose(t *testing.T) {
        <-writeErr
 }
 
-func TestCaseSensitiveMethod(t *testing.T) {
+func TestCaseSensitiveMethod_h1(t *testing.T) { testCaseSensitiveMethod(t, h1Mode) }
+func TestCaseSensitiveMethod_h2(t *testing.T) { testCaseSensitiveMethod(t, h2Mode) }
+func testCaseSensitiveMethod(t *testing.T, h2 bool) {
        defer afterTest(t)
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
                if r.Method != "get" {
                        t.Errorf(`Got method %q; want "get"`, r.Method)
                }
        }))
-       defer ts.Close()
-       req, _ := NewRequest("get", ts.URL, nil)
-       res, err := DefaultClient.Do(req)
+       defer cst.close()
+       req, _ := NewRequest("get", cst.ts.URL, nil)
+       res, err := cst.c.Do(req)
        if err != nil {
                t.Error(err)
                return
        }
+
        res.Body.Close()
 }
 
@@ -2131,6 +2398,49 @@ For:
        ts.Close()
 }
 
+// Tests that a pipelined request causes the first request's Handler's CloseNotify
+// channel to fire. Previously it deadlocked.
+//
+// Issue 13165
+func TestCloseNotifierPipelined(t *testing.T) {
+       defer afterTest(t)
+       gotReq := make(chan bool, 2)
+       sawClose := make(chan bool, 2)
+       ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+               gotReq <- true
+               cc := rw.(CloseNotifier).CloseNotify()
+               <-cc
+               sawClose <- true
+       }))
+       conn, err := net.Dial("tcp", ts.Listener.Addr().String())
+       if err != nil {
+               t.Fatalf("error dialing: %v", err)
+       }
+       diec := make(chan bool, 2)
+       go func() {
+               const req = "GET / HTTP/1.1\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n"
+               _, err = io.WriteString(conn, req+req) // two requests
+               if err != nil {
+                       t.Fatal(err)
+               }
+               <-diec
+               conn.Close()
+       }()
+For:
+       for {
+               select {
+               case <-gotReq:
+                       diec <- true
+               case <-sawClose:
+                       break For
+               case <-time.After(5 * time.Second):
+                       ts.CloseClientConnections()
+                       t.Fatal("timeout")
+               }
+       }
+       ts.Close()
+}
+
 func TestCloseNotifierChanLeak(t *testing.T) {
        defer afterTest(t)
        req := reqBytes("GET / HTTP/1.0\nHost: golang.org")
@@ -2153,6 +2463,114 @@ func TestCloseNotifierChanLeak(t *testing.T) {
        }
 }
 
+// Tests that we can use CloseNotifier in one request, and later call Hijack
+// on a second request on the same connection.
+//
+// It also tests that the connReader stitches together its background
+// 1-byte read for CloseNotifier when CloseNotifier doesn't fire with
+// the rest of the second HTTP later.
+//
+// Issue 9763.
+// HTTP/1-only test. (http2 doesn't have Hijack)
+func TestHijackAfterCloseNotifier(t *testing.T) {
+       defer afterTest(t)
+       script := make(chan string, 2)
+       script <- "closenotify"
+       script <- "hijack"
+       close(script)
+       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+               plan := <-script
+               switch plan {
+               default:
+                       panic("bogus plan; too many requests")
+               case "closenotify":
+                       w.(CloseNotifier).CloseNotify() // discard result
+                       w.Header().Set("X-Addr", r.RemoteAddr)
+               case "hijack":
+                       c, _, err := w.(Hijacker).Hijack()
+                       if err != nil {
+                               t.Errorf("Hijack in Handler: %v", err)
+                               return
+                       }
+                       if _, ok := c.(*net.TCPConn); !ok {
+                               // Verify it's not wrapped in some type.
+                               // Not strictly a go1 compat issue, but in practice it probably is.
+                               t.Errorf("type of hijacked conn is %T; want *net.TCPConn", c)
+                       }
+                       fmt.Fprintf(c, "HTTP/1.0 200 OK\r\nX-Addr: %v\r\nContent-Length: 0\r\n\r\n", r.RemoteAddr)
+                       c.Close()
+                       return
+               }
+       }))
+       defer ts.Close()
+       res1, err := Get(ts.URL)
+       if err != nil {
+               log.Fatal(err)
+       }
+       res2, err := Get(ts.URL)
+       if err != nil {
+               log.Fatal(err)
+       }
+       addr1 := res1.Header.Get("X-Addr")
+       addr2 := res2.Header.Get("X-Addr")
+       if addr1 == "" || addr1 != addr2 {
+               t.Errorf("addr1, addr2 = %q, %q; want same", addr1, addr2)
+       }
+}
+
+func TestHijackBeforeRequestBodyRead(t *testing.T) {
+       defer afterTest(t)
+       var requestBody = bytes.Repeat([]byte("a"), 1<<20)
+       bodyOkay := make(chan bool, 1)
+       gotCloseNotify := make(chan bool, 1)
+       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+               defer close(bodyOkay) // caller will read false if nothing else
+
+               reqBody := r.Body
+               r.Body = nil // to test that server.go doesn't use this value.
+
+               gone := w.(CloseNotifier).CloseNotify()
+               slurp, err := ioutil.ReadAll(reqBody)
+               if err != nil {
+                       t.Errorf("Body read: %v", err)
+                       return
+               }
+               if len(slurp) != len(requestBody) {
+                       t.Errorf("Backend read %d request body bytes; want %d", len(slurp), len(requestBody))
+                       return
+               }
+               if !bytes.Equal(slurp, requestBody) {
+                       t.Error("Backend read wrong request body.") // 1MB; omitting details
+                       return
+               }
+               bodyOkay <- true
+               select {
+               case <-gone:
+                       gotCloseNotify <- true
+               case <-time.After(5 * time.Second):
+                       gotCloseNotify <- false
+               }
+       }))
+       defer ts.Close()
+
+       conn, err := net.Dial("tcp", ts.Listener.Addr().String())
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer conn.Close()
+
+       fmt.Fprintf(conn, "POST / HTTP/1.1\r\nHost: foo\r\nContent-Length: %d\r\n\r\n%s",
+               len(requestBody), requestBody)
+       if !<-bodyOkay {
+               // already failed.
+               return
+       }
+       conn.Close()
+       if !<-gotCloseNotify {
+               t.Error("timeout waiting for CloseNotify")
+       }
+}
+
 func TestOptions(t *testing.T) {
        uric := make(chan string, 2) // only expect 1, but leave space for 2
        mux := NewServeMux()
@@ -2230,7 +2648,7 @@ func TestHeaderToWire(t *testing.T) {
                                        return errors.New("no content-length")
                                }
                                if !strings.Contains(got, "Content-Type: text/plain") {
-                                       return errors.New("no content-length")
+                                       return errors.New("no content-type")
                                }
                                return nil
                        },
@@ -2302,7 +2720,7 @@ func TestHeaderToWire(t *testing.T) {
                                        return errors.New("header appeared from after WriteHeader")
                                }
                                if !strings.Contains(got, "Content-Type: some/type") {
-                                       return errors.New("wrong content-length")
+                                       return errors.New("wrong content-type")
                                }
                                return nil
                        },
@@ -2315,7 +2733,7 @@ func TestHeaderToWire(t *testing.T) {
                        },
                        check: func(got string) error {
                                if !strings.Contains(got, "Content-Type: text/html") {
-                                       return errors.New("wrong content-length; want html")
+                                       return errors.New("wrong content-type; want html")
                                }
                                return nil
                        },
@@ -2328,7 +2746,7 @@ func TestHeaderToWire(t *testing.T) {
                        },
                        check: func(got string) error {
                                if !strings.Contains(got, "Content-Type: some/type") {
-                                       return errors.New("wrong content-length; want html")
+                                       return errors.New("wrong content-type; want html")
                                }
                                return nil
                        },
@@ -2339,7 +2757,7 @@ func TestHeaderToWire(t *testing.T) {
                        },
                        check: func(got string) error {
                                if !strings.Contains(got, "Content-Type: text/plain") {
-                                       return errors.New("wrong content-length; want text/plain")
+                                       return errors.New("wrong content-type; want text/plain")
                                }
                                if !strings.Contains(got, "Content-Length: 0") {
                                        return errors.New("want 0 content-length")
@@ -2369,7 +2787,7 @@ func TestHeaderToWire(t *testing.T) {
                                if !strings.Contains(got, "404") {
                                        return errors.New("wrong status")
                                }
-                               if strings.Contains(got, "Some-Header") {
+                               if strings.Contains(got, "Too-Late") {
                                        return errors.New("shouldn't have seen Too-Late")
                                }
                                return nil
@@ -2503,7 +2921,7 @@ func TestHTTP10ConnectionHeader(t *testing.T) {
        defer afterTest(t)
 
        mux := NewServeMux()
-       mux.Handle("/", HandlerFunc(func(resp ResponseWriter, req *Request) {}))
+       mux.Handle("/", HandlerFunc(func(ResponseWriter, *Request) {}))
        ts := httptest.NewServer(mux)
        defer ts.Close()
 
@@ -2552,11 +2970,13 @@ func TestHTTP10ConnectionHeader(t *testing.T) {
 }
 
 // See golang.org/issue/5660
-func TestServerReaderFromOrder(t *testing.T) {
+func TestServerReaderFromOrder_h1(t *testing.T) { testServerReaderFromOrder(t, h1Mode) }
+func TestServerReaderFromOrder_h2(t *testing.T) { testServerReaderFromOrder(t, h2Mode) }
+func testServerReaderFromOrder(t *testing.T, h2 bool) {
        defer afterTest(t)
        pr, pw := io.Pipe()
        const size = 3 << 20
-       ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(rw ResponseWriter, req *Request) {
                rw.Header().Set("Content-Type", "text/plain") // prevent sniffing path
                done := make(chan bool)
                go func() {
@@ -2576,13 +2996,13 @@ func TestServerReaderFromOrder(t *testing.T) {
                pw.Close()
                <-done
        }))
-       defer ts.Close()
+       defer cst.close()
 
-       req, err := NewRequest("POST", ts.URL, io.LimitReader(neverEnding('a'), size))
+       req, err := NewRequest("POST", cst.ts.URL, io.LimitReader(neverEnding('a'), size))
        if err != nil {
                t.Fatal(err)
        }
-       res, err := DefaultClient.Do(req)
+       res, err := cst.c.Do(req)
        if err != nil {
                t.Fatal(err)
        }
@@ -2612,9 +3032,9 @@ func TestCodesPreventingContentTypeAndBody(t *testing.T) {
                        "GET / HTTP/1.0",
                        "GET /header HTTP/1.0",
                        "GET /more HTTP/1.0",
-                       "GET / HTTP/1.1",
-                       "GET /header HTTP/1.1",
-                       "GET /more HTTP/1.1",
+                       "GET / HTTP/1.1\nHost: foo",
+                       "GET /header HTTP/1.1\nHost: foo",
+                       "GET /more HTTP/1.1\nHost: foo",
                } {
                        got := ht.rawResponse(req)
                        wantStatus := fmt.Sprintf("%d %s", code, StatusText(code))
@@ -2635,7 +3055,7 @@ func TestContentTypeOkayOn204(t *testing.T) {
                w.Header().Set("Content-Type", "foo/bar")
                w.WriteHeader(204)
        }))
-       got := ht.rawResponse("GET / HTTP/1.1")
+       got := ht.rawResponse("GET / HTTP/1.1\nHost: foo")
        if !strings.Contains(got, "Content-Type: foo/bar") {
                t.Errorf("Response = %q; want Content-Type: foo/bar", got)
        }
@@ -2650,45 +3070,101 @@ func TestContentTypeOkayOn204(t *testing.T) {
 // proxy).  So then two people own that Request.Body (both the server
 // and the http client), and both think they can close it on failure.
 // Therefore, all incoming server requests Bodies need to be thread-safe.
-func TestTransportAndServerSharedBodyRace(t *testing.T) {
+func TestTransportAndServerSharedBodyRace_h1(t *testing.T) {
+       testTransportAndServerSharedBodyRace(t, h1Mode)
+}
+func TestTransportAndServerSharedBodyRace_h2(t *testing.T) {
+       testTransportAndServerSharedBodyRace(t, h2Mode)
+}
+func testTransportAndServerSharedBodyRace(t *testing.T, h2 bool) {
        defer afterTest(t)
 
        const bodySize = 1 << 20
 
+       // errorf is like t.Errorf, but also writes to println.  When
+       // this test fails, it hangs. This helps debugging and I've
+       // added this enough times "temporarily".  It now gets added
+       // full time.
+       errorf := func(format string, args ...interface{}) {
+               v := fmt.Sprintf(format, args...)
+               println(v)
+               t.Error(v)
+       }
+
        unblockBackend := make(chan bool)
-       backend := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
-               io.CopyN(rw, req.Body, bodySize)
+       backend := newClientServerTest(t, h2, HandlerFunc(func(rw ResponseWriter, req *Request) {
+               gone := rw.(CloseNotifier).CloseNotify()
+               didCopy := make(chan interface{})
+               go func() {
+                       n, err := io.CopyN(rw, req.Body, bodySize)
+                       didCopy <- []interface{}{n, err}
+               }()
+               isGone := false
+       Loop:
+               for {
+                       select {
+                       case <-didCopy:
+                               break Loop
+                       case <-gone:
+                               isGone = true
+                       case <-time.After(time.Second):
+                               println("1 second passes in backend, proxygone=", isGone)
+                       }
+               }
                <-unblockBackend
        }))
-       defer backend.Close()
+       var quitTimer *time.Timer
+       defer func() { quitTimer.Stop() }()
+       defer backend.close()
 
        backendRespc := make(chan *Response, 1)
-       proxy := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
-               req2, _ := NewRequest("POST", backend.URL, req.Body)
+       var proxy *clientServerTest
+       proxy = newClientServerTest(t, h2, HandlerFunc(func(rw ResponseWriter, req *Request) {
+               req2, _ := NewRequest("POST", backend.ts.URL, req.Body)
                req2.ContentLength = bodySize
+               cancel := make(chan struct{})
+               req2.Cancel = cancel
 
-               bresp, err := DefaultClient.Do(req2)
+               bresp, err := proxy.c.Do(req2)
                if err != nil {
-                       t.Errorf("Proxy outbound request: %v", err)
+                       errorf("Proxy outbound request: %v", err)
                        return
                }
                _, err = io.CopyN(ioutil.Discard, bresp.Body, bodySize/2)
                if err != nil {
-                       t.Errorf("Proxy copy error: %v", err)
+                       errorf("Proxy copy error: %v", err)
                        return
                }
                backendRespc <- bresp // to close later
 
-               // Try to cause a race: Both the DefaultTransport and the proxy handler's Server
+               // Try to cause a race: Both the Transport and the proxy handler's Server
                // will try to read/close req.Body (aka req2.Body)
-               DefaultTransport.(*Transport).CancelRequest(req2)
+               if h2 {
+                       close(cancel)
+               } else {
+                       proxy.c.Transport.(*Transport).CancelRequest(req2)
+               }
                rw.Write([]byte("OK"))
        }))
-       defer proxy.Close()
+       defer proxy.close()
+       defer func() {
+               // Before we shut down our two httptest.Servers, start a timer.
+               // We choose 7 seconds because httptest.Server starts logging
+               // warnings to stderr at 5 seconds. If we don't disarm this bomb
+               // in 7 seconds (after the two httptest.Server.Close calls above),
+               // then we explode with stacks.
+               quitTimer = time.AfterFunc(7*time.Second, func() {
+                       debug.SetTraceback("ALL")
+                       stacks := make([]byte, 1<<20)
+                       stacks = stacks[:runtime.Stack(stacks, true)]
+                       fmt.Fprintf(os.Stderr, "%s", stacks)
+                       log.Fatalf("Timeout.")
+               })
+       }()
 
        defer close(unblockBackend)
-       req, _ := NewRequest("POST", proxy.URL, io.LimitReader(neverEnding('a'), bodySize))
-       res, err := DefaultClient.Do(req)
+       req, _ := NewRequest("POST", proxy.ts.URL, io.LimitReader(neverEnding('a'), bodySize))
+       res, err := proxy.c.Do(req)
        if err != nil {
                t.Fatalf("Original request: %v", err)
        }
@@ -2699,7 +3175,7 @@ func TestTransportAndServerSharedBodyRace(t *testing.T) {
        case res := <-backendRespc:
                res.Body.Close()
        default:
-               // We failed earlier. (e.g. on DefaultClient.Do(req2))
+               // We failed earlier. (e.g. on proxy.c.Do(req2))
        }
 }
 
@@ -2863,6 +3339,7 @@ func TestServerConnState(t *testing.T) {
                if _, err := io.WriteString(c, "BOGUS REQUEST\r\n\r\n"); err != nil {
                        t.Fatal(err)
                }
+               c.Read(make([]byte, 1)) // block until server hangs up on us
                c.Close()
        }
 
@@ -2896,9 +3373,14 @@ func TestServerConnState(t *testing.T) {
        }
        logString := func(m map[int][]ConnState) string {
                var b bytes.Buffer
-               for id, l := range m {
+               var keys []int
+               for id := range m {
+                       keys = append(keys, id)
+               }
+               sort.Ints(keys)
+               for _, id := range keys {
                        fmt.Fprintf(&b, "Conn %d: ", id)
-                       for _, s := range l {
+                       for _, s := range m[id] {
                                fmt.Fprintf(&b, "%s ", s)
                        }
                        b.WriteString("\n")
@@ -2959,20 +3441,22 @@ func TestServerKeepAlivesEnabled(t *testing.T) {
 }
 
 // golang.org/issue/7856
-func TestServerEmptyBodyRace(t *testing.T) {
+func TestServerEmptyBodyRace_h1(t *testing.T) { testServerEmptyBodyRace(t, h1Mode) }
+func TestServerEmptyBodyRace_h2(t *testing.T) { testServerEmptyBodyRace(t, h2Mode) }
+func testServerEmptyBodyRace(t *testing.T, h2 bool) {
        defer afterTest(t)
        var n int32
-       ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(rw ResponseWriter, req *Request) {
                atomic.AddInt32(&n, 1)
        }))
-       defer ts.Close()
+       defer cst.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)
+                       res, err := cst.c.Get(cst.ts.URL)
                        if err != nil {
                                t.Error(err)
                                return
@@ -3025,10 +3509,7 @@ func (c *closeWriteTestConn) CloseWrite() error {
 func TestCloseWrite(t *testing.T) {
        var srv Server
        var testConn closeWriteTestConn
-       c, err := ExportServerNewConn(&srv, &testConn)
-       if err != nil {
-               t.Fatal(err)
-       }
+       c := ExportServerNewConn(&srv, &testConn)
        ExportCloseWriteAndWait(c)
        if !testConn.didCloseWrite {
                t.Error("didn't see CloseWrite call")
@@ -3193,6 +3674,33 @@ func TestTolerateCRLFBeforeRequestLine(t *testing.T) {
        }
 }
 
+func TestIssue13893_Expect100(t *testing.T) {
+       // test that the Server doesn't filter out Expect headers.
+       req := reqBytes(`PUT /readbody HTTP/1.1
+User-Agent: PycURL/7.22.0
+Host: 127.0.0.1:9000
+Accept: */*
+Expect: 100-continue
+Content-Length: 10
+
+HelloWorld
+
+`)
+       var buf bytes.Buffer
+       conn := &rwTestConn{
+               Reader: bytes.NewReader(req),
+               Writer: &buf,
+               closec: make(chan bool, 1),
+       }
+       ln := &oneConnListener{conn: conn}
+       go Serve(ln, HandlerFunc(func(w ResponseWriter, r *Request) {
+               if _, ok := r.Header["Expect"]; !ok {
+                       t.Error("Expect header should not be filtered out")
+               }
+       }))
+       <-conn.closec
+}
+
 func TestIssue11549_Expect100(t *testing.T) {
        req := reqBytes(`PUT /readbody HTTP/1.1
 User-Agent: PycURL/7.22.0
@@ -3260,6 +3768,122 @@ func TestHandlerFinishSkipBigContentLengthRead(t *testing.T) {
        }
 }
 
+func TestHandlerSetsBodyNil_h1(t *testing.T) { testHandlerSetsBodyNil(t, h1Mode) }
+func TestHandlerSetsBodyNil_h2(t *testing.T) { testHandlerSetsBodyNil(t, h2Mode) }
+func testHandlerSetsBodyNil(t *testing.T, h2 bool) {
+       defer afterTest(t)
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+               r.Body = nil
+               fmt.Fprintf(w, "%v", r.RemoteAddr)
+       }))
+       defer cst.close()
+       get := func() string {
+               res, err := cst.c.Get(cst.ts.URL)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               defer res.Body.Close()
+               slurp, err := ioutil.ReadAll(res.Body)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               return string(slurp)
+       }
+       a, b := get(), get()
+       if a != b {
+               t.Errorf("Failed to reuse connections between requests: %v vs %v", a, b)
+       }
+}
+
+// Test that we validate the Host header.
+// Issue 11206 (invalid bytes in Host) and 13624 (Host present in HTTP/1.1)
+func TestServerValidatesHostHeader(t *testing.T) {
+       tests := []struct {
+               proto string
+               host  string
+               want  int
+       }{
+               {"HTTP/1.1", "", 400},
+               {"HTTP/1.1", "Host: \r\n", 200},
+               {"HTTP/1.1", "Host: 1.2.3.4\r\n", 200},
+               {"HTTP/1.1", "Host: foo.com\r\n", 200},
+               {"HTTP/1.1", "Host: foo-bar_baz.com\r\n", 200},
+               {"HTTP/1.1", "Host: foo.com:80\r\n", 200},
+               {"HTTP/1.1", "Host: ::1\r\n", 200},
+               {"HTTP/1.1", "Host: [::1]\r\n", 200}, // questionable without port, but accept it
+               {"HTTP/1.1", "Host: [::1]:80\r\n", 200},
+               {"HTTP/1.1", "Host: [::1%25en0]:80\r\n", 200},
+               {"HTTP/1.1", "Host: 1.2.3.4\r\n", 200},
+               {"HTTP/1.1", "Host: \x06\r\n", 400},
+               {"HTTP/1.1", "Host: \xff\r\n", 400},
+               {"HTTP/1.1", "Host: {\r\n", 400},
+               {"HTTP/1.1", "Host: }\r\n", 400},
+               {"HTTP/1.1", "Host: first\r\nHost: second\r\n", 400},
+
+               // HTTP/1.0 can lack a host header, but if present
+               // must play by the rules too:
+               {"HTTP/1.0", "", 200},
+               {"HTTP/1.0", "Host: first\r\nHost: second\r\n", 400},
+               {"HTTP/1.0", "Host: \xff\r\n", 400},
+       }
+       for _, tt := range tests {
+               conn := &testConn{closec: make(chan bool, 1)}
+               io.WriteString(&conn.readBuf, "GET / "+tt.proto+"\r\n"+tt.host+"\r\n")
+
+               ln := &oneConnListener{conn}
+               go Serve(ln, HandlerFunc(func(ResponseWriter, *Request) {}))
+               <-conn.closec
+               res, err := ReadResponse(bufio.NewReader(&conn.writeBuf), nil)
+               if err != nil {
+                       t.Errorf("For %s %q, ReadResponse: %v", tt.proto, tt.host, res)
+                       continue
+               }
+               if res.StatusCode != tt.want {
+                       t.Errorf("For %s %q, Status = %d; want %d", tt.proto, tt.host, res.StatusCode, tt.want)
+               }
+       }
+}
+
+// Test that we validate the valid bytes in HTTP/1 headers.
+// Issue 11207.
+func TestServerValidatesHeaders(t *testing.T) {
+       tests := []struct {
+               header string
+               want   int
+       }{
+               {"", 200},
+               {"Foo: bar\r\n", 200},
+               {"X-Foo: bar\r\n", 200},
+               {"Foo: a space\r\n", 200},
+
+               {"A space: foo\r\n", 400},    // space in header
+               {"foo\xffbar: foo\r\n", 400}, // binary in header
+               {"foo\x00bar: foo\r\n", 400}, // binary in header
+
+               {"foo: foo foo\r\n", 200},    // LWS space is okay
+               {"foo: foo\tfoo\r\n", 200},   // LWS tab is okay
+               {"foo: foo\x00foo\r\n", 400}, // CTL 0x00 in value is bad
+               {"foo: foo\x7ffoo\r\n", 400}, // CTL 0x7f in value is bad
+               {"foo: foo\xfffoo\r\n", 200}, // non-ASCII high octets in value are fine
+       }
+       for _, tt := range tests {
+               conn := &testConn{closec: make(chan bool, 1)}
+               io.WriteString(&conn.readBuf, "GET / HTTP/1.1\r\nHost: foo\r\n"+tt.header+"\r\n")
+
+               ln := &oneConnListener{conn}
+               go Serve(ln, HandlerFunc(func(ResponseWriter, *Request) {}))
+               <-conn.closec
+               res, err := ReadResponse(bufio.NewReader(&conn.writeBuf), nil)
+               if err != nil {
+                       t.Errorf("For %q, ReadResponse: %v", tt.header, res)
+                       continue
+               }
+               if res.StatusCode != tt.want {
+                       t.Errorf("For %q, Status = %d; want %d", tt.header, res.StatusCode, tt.want)
+               }
+       }
+}
+
 func BenchmarkClientServer(b *testing.B) {
        b.ReportAllocs()
        b.StopTimer()
@@ -3685,3 +4309,35 @@ Host: golang.org
                <-conn.closec
        }
 }
+
+func BenchmarkCloseNotifier(b *testing.B) {
+       b.ReportAllocs()
+       b.StopTimer()
+       sawClose := make(chan bool)
+       ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+               <-rw.(CloseNotifier).CloseNotify()
+               sawClose <- true
+       }))
+       defer ts.Close()
+       tot := time.NewTimer(5 * time.Second)
+       defer tot.Stop()
+       b.StartTimer()
+       for i := 0; i < b.N; i++ {
+               conn, err := net.Dial("tcp", ts.Listener.Addr().String())
+               if err != nil {
+                       b.Fatalf("error dialing: %v", err)
+               }
+               _, err = fmt.Fprintf(conn, "GET / HTTP/1.1\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n")
+               if err != nil {
+                       b.Fatal(err)
+               }
+               conn.Close()
+               tot.Reset(5 * time.Second)
+               select {
+               case <-sawClose:
+               case <-tot.C:
+                       b.Fatal("timeout")
+               }
+       }
+       b.StopTimer()
+}
index a3e43555bb37b4f120deeec2e5bd16277976b29d..004a1f92fc4da31f03a67360b16acc51b4dd4117 100644 (file)
@@ -8,6 +8,7 @@ package http
 
 import (
        "bufio"
+       "bytes"
        "crypto/tls"
        "errors"
        "fmt"
@@ -35,26 +36,33 @@ var (
        ErrContentLength   = errors.New("Conn.Write wrote more than the declared Content-Length")
 )
 
-// Objects implementing the Handler interface can be
-// registered to serve a particular path or subtree
-// in the HTTP server.
+// A Handler responds to an HTTP request.
 //
 // ServeHTTP should write reply headers and data to the ResponseWriter
-// and then return.  Returning signals that the request is finished
-// and that the HTTP server can move on to the next request on
-// the connection.
+// and then return. Returning signals that the request is finished; it
+// is not valid to use the ResponseWriter or read from the
+// Request.Body after or concurrently with the completion of the
+// ServeHTTP call.
+//
+// Depending on the HTTP client software, HTTP protocol version, and
+// any intermediaries between the client and the Go server, it may not
+// be possible to read from the Request.Body after writing to the
+// ResponseWriter. Cautious handlers should read the Request.Body
+// first, and then reply.
 //
 // If ServeHTTP panics, the server (the caller of ServeHTTP) assumes
 // that the effect of the panic was isolated to the active request.
 // It recovers the panic, logs a stack trace to the server error log,
 // and hangs up the connection.
-//
 type Handler interface {
        ServeHTTP(ResponseWriter, *Request)
 }
 
 // A ResponseWriter interface is used by an HTTP handler to
 // construct an HTTP response.
+//
+// A ResponseWriter may not be used after the Handler.ServeHTTP method
+// has returned.
 type ResponseWriter interface {
        // Header returns the header map that will be sent by
        // WriteHeader. Changing the header after a call to
@@ -114,28 +122,76 @@ type Hijacker interface {
 // This mechanism can be used to cancel long operations on the server
 // if the client has disconnected before the response is ready.
 type CloseNotifier interface {
-       // CloseNotify returns a channel that receives a single value
-       // when the client connection has gone away.
+       // CloseNotify returns a channel that receives at most a
+       // single value (true) when the client connection has gone
+       // away.
+       //
+       // CloseNotify may wait to notify until Request.Body has been
+       // fully read.
+       //
+       // After the Handler has returned, there is no guarantee
+       // that the channel receives a value.
+       //
+       // If the protocol is HTTP/1.1 and CloseNotify is called while
+       // processing an idempotent request (such a GET) while
+       // HTTP/1.1 pipelining is in use, the arrival of a subsequent
+       // pipelined request may cause a value to be sent on the
+       // returned channel. In practice HTTP/1.1 pipelining is not
+       // enabled in browsers and not seen often in the wild. If this
+       // is a problem, use HTTP/2 or only use CloseNotify on methods
+       // such as POST.
        CloseNotify() <-chan bool
 }
 
 // A conn represents the server side of an HTTP connection.
 type conn struct {
-       remoteAddr string               // network address of remote side
-       server     *Server              // the Server on which the connection arrived
-       rwc        net.Conn             // i/o connection
-       w          io.Writer            // checkConnErrorWriter's copy of wrc, not zeroed on Hijack
-       werr       error                // any errors writing to w
-       sr         liveSwitchReader     // where the LimitReader reads from; usually the rwc
-       lr         *io.LimitedReader    // io.LimitReader(sr)
-       buf        *bufio.ReadWriter    // buffered(lr,rwc), reading from bufio->limitReader->sr->rwc
-       tlsState   *tls.ConnectionState // or nil when not using TLS
-       lastMethod string               // method of previous request, or ""
-
-       mu           sync.Mutex // guards the following
-       clientGone   bool       // if client has disconnected mid-request
-       closeNotifyc chan bool  // made lazily
-       hijackedv    bool       // connection has been hijacked by handler
+       // server is the server on which the connection arrived.
+       // Immutable; never nil.
+       server *Server
+
+       // rwc is the underlying network connection.
+       // This is never wrapped by other types and is the value given out
+       // to CloseNotifier callers. It is usually of type *net.TCPConn or
+       // *tls.Conn.
+       rwc net.Conn
+
+       // remoteAddr is rwc.RemoteAddr().String(). It is not populated synchronously
+       // inside the Listener's Accept goroutine, as some implementations block.
+       // It is populated immediately inside the (*conn).serve goroutine.
+       // This is the value of a Handler's (*Request).RemoteAddr.
+       remoteAddr string
+
+       // tlsState is the TLS connection state when using TLS.
+       // nil means not TLS.
+       tlsState *tls.ConnectionState
+
+       // werr is set to the first write error to rwc.
+       // It is set via checkConnErrorWriter{w}, where bufw writes.
+       werr error
+
+       // r is bufr's read source. It's a wrapper around rwc that provides
+       // io.LimitedReader-style limiting (while reading request headers)
+       // and functionality to support CloseNotifier. See *connReader docs.
+       r *connReader
+
+       // bufr reads from r.
+       // Users of bufr must hold mu.
+       bufr *bufio.Reader
+
+       // bufw writes to checkConnErrorWriter{c}, which populates werr on error.
+       bufw *bufio.Writer
+
+       // lastMethod is the method of the most recent request
+       // on this connection, if any.
+       lastMethod string
+
+       // mu guards hijackedv, use of bufr, (*response).closeNotifyCh.
+       mu sync.Mutex
+
+       // hijackedv is whether this connection has been hijacked
+       // by a Handler with the Hijacker interface.
+       // It is guarded by mu.
+       hijackedv bool
 }
 
 func (c *conn) hijacked() bool {
@@ -144,81 +200,18 @@ func (c *conn) hijacked() bool {
        return c.hijackedv
 }
 
-func (c *conn) hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
-       c.mu.Lock()
-       defer c.mu.Unlock()
+// c.mu must be held.
+func (c *conn) hijackLocked() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
        if c.hijackedv {
                return nil, nil, ErrHijacked
        }
-       if c.closeNotifyc != nil {
-               return nil, nil, errors.New("http: Hijack is incompatible with use of CloseNotifier")
-       }
        c.hijackedv = true
        rwc = c.rwc
-       buf = c.buf
-       c.rwc = nil
-       c.buf = nil
+       buf = bufio.NewReadWriter(c.bufr, bufio.NewWriter(rwc))
        c.setState(rwc, StateHijacked)
        return
 }
 
-func (c *conn) closeNotify() <-chan bool {
-       c.mu.Lock()
-       defer c.mu.Unlock()
-       if c.closeNotifyc == nil {
-               c.closeNotifyc = make(chan bool, 1)
-               if c.hijackedv {
-                       // to obey the function signature, even though
-                       // it'll never receive a value.
-                       return c.closeNotifyc
-               }
-               pr, pw := io.Pipe()
-
-               readSource := c.sr.r
-               c.sr.Lock()
-               c.sr.r = pr
-               c.sr.Unlock()
-               go func() {
-                       _, err := io.Copy(pw, readSource)
-                       if err == nil {
-                               err = io.EOF
-                       }
-                       pw.CloseWithError(err)
-                       c.noteClientGone()
-               }()
-       }
-       return c.closeNotifyc
-}
-
-func (c *conn) noteClientGone() {
-       c.mu.Lock()
-       defer c.mu.Unlock()
-       if c.closeNotifyc != nil && !c.clientGone {
-               c.closeNotifyc <- true
-       }
-       c.clientGone = true
-}
-
-// A switchWriter can have its Writer changed at runtime.
-// It's not safe for concurrent Writes and switches.
-type switchWriter struct {
-       io.Writer
-}
-
-// A liveSwitchReader can have its Reader changed at runtime. It's
-// safe for concurrent reads and switches, if its mutex is held.
-type liveSwitchReader struct {
-       sync.Mutex
-       r io.Reader
-}
-
-func (sr *liveSwitchReader) Read(p []byte) (n int, err error) {
-       sr.Lock()
-       r := sr.r
-       sr.Unlock()
-       return r.Read(p)
-}
-
 // This should be >= 512 bytes for DetectContentType,
 // but otherwise it's somewhat arbitrary.
 const bufferBeforeChunkingSize = 2048
@@ -265,15 +258,15 @@ func (cw *chunkWriter) Write(p []byte) (n int, err error) {
                return len(p), nil
        }
        if cw.chunking {
-               _, err = fmt.Fprintf(cw.res.conn.buf, "%x\r\n", len(p))
+               _, err = fmt.Fprintf(cw.res.conn.bufw, "%x\r\n", len(p))
                if err != nil {
                        cw.res.conn.rwc.Close()
                        return
                }
        }
-       n, err = cw.res.conn.buf.Write(p)
+       n, err = cw.res.conn.bufw.Write(p)
        if cw.chunking && err == nil {
-               _, err = cw.res.conn.buf.Write(crlf)
+               _, err = cw.res.conn.bufw.Write(crlf)
        }
        if err != nil {
                cw.res.conn.rwc.Close()
@@ -285,7 +278,7 @@ func (cw *chunkWriter) flush() {
        if !cw.wroteHeader {
                cw.writeHeader(nil)
        }
-       cw.res.conn.buf.Flush()
+       cw.res.conn.bufw.Flush()
 }
 
 func (cw *chunkWriter) close() {
@@ -293,7 +286,7 @@ func (cw *chunkWriter) close() {
                cw.writeHeader(nil)
        }
        if cw.chunking {
-               bw := cw.res.conn.buf // conn's bufio writer
+               bw := cw.res.conn.bufw // conn's bufio writer
                // zero chunk to mark EOF
                bw.WriteString("0\r\n")
                if len(cw.res.trailers) > 0 {
@@ -315,12 +308,12 @@ func (cw *chunkWriter) close() {
 type response struct {
        conn          *conn
        req           *Request // request for this response
-       wroteHeader   bool     // reply header has been (logically) written
-       wroteContinue bool     // 100 Continue response was written
+       reqBody       io.ReadCloser
+       wroteHeader   bool // reply header has been (logically) written
+       wroteContinue bool // 100 Continue response was written
 
        w  *bufio.Writer // buffers output in chunks to chunkWriter
        cw chunkWriter
-       sw *switchWriter // of the bufio.Writer, for return to putBufioWriter
 
        // handlerHeader is the Header that Handlers get access to,
        // which may be retained and mutated even after WriteHeader.
@@ -354,13 +347,22 @@ type response struct {
        // written.
        trailers []string
 
-       handlerDone bool // set true when the handler exits
+       handlerDone atomicBool // set true when the handler exits
 
        // Buffers for Date and Content-Length
        dateBuf [len(TimeFormat)]byte
        clenBuf [10]byte
+
+       // closeNotifyCh is non-nil once CloseNotify is called.
+       // Guarded by conn.mu
+       closeNotifyCh <-chan bool
 }
 
+type atomicBool int32
+
+func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
+func (b *atomicBool) setTrue()    { atomic.StoreInt32((*int32)(b), 1) }
+
 // declareTrailer is called for each Trailer header when the
 // response header is written. It notes that a header will need to be
 // written in the trailers at the end of the response.
@@ -423,7 +425,9 @@ func (w *response) ReadFrom(src io.Reader) (n int64, err error) {
                return 0, err
        }
        if !ok || !regFile {
-               return io.Copy(writerOnly{w}, src)
+               bufp := copyBufPool.Get().(*[]byte)
+               defer copyBufPool.Put(bufp)
+               return io.CopyBuffer(writerOnly{w}, src, *bufp)
        }
 
        // sendfile path:
@@ -456,29 +460,88 @@ func (w *response) ReadFrom(src io.Reader) (n int64, err error) {
        return n, err
 }
 
-// noLimit is an effective infinite upper bound for io.LimitedReader
-const noLimit int64 = (1 << 63) - 1
-
 // debugServerConnections controls whether all server connections are wrapped
 // with a verbose logging wrapper.
 const debugServerConnections = false
 
 // Create new connection from rwc.
-func (srv *Server) newConn(rwc net.Conn) (c *conn, err error) {
-       c = new(conn)
-       c.remoteAddr = rwc.RemoteAddr().String()
-       c.server = srv
-       c.rwc = rwc
-       c.w = rwc
+func (srv *Server) newConn(rwc net.Conn) *conn {
+       c := &conn{
+               server: srv,
+               rwc:    rwc,
+       }
        if debugServerConnections {
                c.rwc = newLoggingConn("server", c.rwc)
        }
-       c.sr.r = c.rwc
-       c.lr = io.LimitReader(&c.sr, noLimit).(*io.LimitedReader)
-       br := newBufioReader(c.lr)
-       bw := newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)
-       c.buf = bufio.NewReadWriter(br, bw)
-       return c, nil
+       return c
+}
+
+type readResult struct {
+       n   int
+       err error
+       b   byte // byte read, if n == 1
+}
+
+// connReader is the io.Reader wrapper used by *conn. It combines a
+// selectively-activated io.LimitedReader (to bound request header
+// read sizes) with support for selectively keeping an io.Reader.Read
+// call blocked in a background goroutine to wait for activity and
+// trigger a CloseNotifier channel.
+type connReader struct {
+       r      io.Reader
+       remain int64 // bytes remaining
+
+       // ch is non-nil if a background read is in progress.
+       // It is guarded by conn.mu.
+       ch chan readResult
+}
+
+func (cr *connReader) setReadLimit(remain int64) { cr.remain = remain }
+func (cr *connReader) setInfiniteReadLimit()     { cr.remain = 1<<63 - 1 }
+func (cr *connReader) hitReadLimit() bool        { return cr.remain <= 0 }
+
+func (cr *connReader) Read(p []byte) (n int, err error) {
+       if cr.hitReadLimit() {
+               return 0, io.EOF
+       }
+       if len(p) == 0 {
+               return
+       }
+       if int64(len(p)) > cr.remain {
+               p = p[:cr.remain]
+       }
+
+       // Is a background read (started by CloseNotifier) already in
+       // flight? If so, wait for it and use its result.
+       ch := cr.ch
+       if ch != nil {
+               cr.ch = nil
+               res := <-ch
+               if res.n == 1 {
+                       p[0] = res.b
+                       cr.remain -= 1
+               }
+               return res.n, res.err
+       }
+       n, err = cr.r.Read(p)
+       cr.remain -= int64(n)
+       return
+}
+
+func (cr *connReader) startBackgroundRead(onReadComplete func()) {
+       if cr.ch != nil {
+               // Background read already started.
+               return
+       }
+       cr.ch = make(chan readResult, 1)
+       go cr.closeNotifyAwaitActivityRead(cr.ch, onReadComplete)
+}
+
+func (cr *connReader) closeNotifyAwaitActivityRead(ch chan<- readResult, onReadComplete func()) {
+       var buf [1]byte
+       n, err := cr.r.Read(buf[:1])
+       onReadComplete()
+       ch <- readResult{n, err, buf[0]}
 }
 
 var (
@@ -487,6 +550,13 @@ var (
        bufioWriter4kPool sync.Pool
 )
 
+var copyBufPool = sync.Pool{
+       New: func() interface{} {
+               b := make([]byte, 32*1024)
+               return &b
+       },
+}
+
 func bufioWriterPool(size int) *sync.Pool {
        switch size {
        case 2 << 10:
@@ -544,7 +614,7 @@ func (srv *Server) maxHeaderBytes() int {
        return DefaultMaxHeaderBytes
 }
 
-func (srv *Server) initialLimitedReaderSize() int64 {
+func (srv *Server) initialReadLimitSize() int64 {
        return int64(srv.maxHeaderBytes()) + 4096 // bufio slop
 }
 
@@ -563,8 +633,8 @@ func (ecr *expectContinueReader) Read(p []byte) (n int, err error) {
        }
        if !ecr.resp.wroteContinue && !ecr.resp.conn.hijacked() {
                ecr.resp.wroteContinue = true
-               ecr.resp.conn.buf.WriteString("HTTP/1.1 100 Continue\r\n\r\n")
-               ecr.resp.conn.buf.Flush()
+               ecr.resp.conn.bufw.WriteString("HTTP/1.1 100 Continue\r\n\r\n")
+               ecr.resp.conn.bufw.Flush()
        }
        n, err = ecr.readCloser.Read(p)
        if err == io.EOF {
@@ -578,10 +648,12 @@ func (ecr *expectContinueReader) Close() error {
        return ecr.readCloser.Close()
 }
 
-// TimeFormat is the time format to use with
-// time.Parse and time.Time.Format when parsing
-// or generating times in HTTP headers.
-// It is like time.RFC1123 but hard codes GMT as the time zone.
+// TimeFormat is the time format to use when generating times in HTTP
+// headers. It is like time.RFC1123 but hard-codes GMT as the time
+// zone. The time being formatted must be in UTC for Format to
+// generate the correct format.
+//
+// For parsing this time format, see ParseTime.
 const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
 
 // appendTime is a non-allocating version of []byte(t.UTC().Format(TimeFormat))
@@ -623,21 +695,45 @@ func (c *conn) readRequest() (w *response, err error) {
                }()
        }
 
-       c.lr.N = c.server.initialLimitedReaderSize()
+       c.r.setReadLimit(c.server.initialReadLimitSize())
+       c.mu.Lock() // while using bufr
        if c.lastMethod == "POST" {
                // RFC 2616 section 4.1 tolerance for old buggy clients.
-               peek, _ := c.buf.Reader.Peek(4) // ReadRequest will get err below
-               c.buf.Reader.Discard(numLeadingCRorLF(peek))
+               peek, _ := c.bufr.Peek(4) // ReadRequest will get err below
+               c.bufr.Discard(numLeadingCRorLF(peek))
        }
-       var req *Request
-       if req, err = ReadRequest(c.buf.Reader); err != nil {
-               if c.lr.N == 0 {
+       req, err := readRequest(c.bufr, keepHostHeader)
+       c.mu.Unlock()
+       if err != nil {
+               if c.r.hitReadLimit() {
                        return nil, errTooLarge
                }
                return nil, err
        }
-       c.lr.N = noLimit
        c.lastMethod = req.Method
+       c.r.setInfiniteReadLimit()
+
+       hosts, haveHost := req.Header["Host"]
+       if req.ProtoAtLeast(1, 1) && (!haveHost || len(hosts) == 0) {
+               return nil, badRequestError("missing required Host header")
+       }
+       if len(hosts) > 1 {
+               return nil, badRequestError("too many Host headers")
+       }
+       if len(hosts) == 1 && !validHostHeader(hosts[0]) {
+               return nil, badRequestError("malformed Host header")
+       }
+       for k, vv := range req.Header {
+               if !validHeaderName(k) {
+                       return nil, badRequestError("invalid header name")
+               }
+               for _, v := range vv {
+                       if !validHeaderValue(v) {
+                               return nil, badRequestError("invalid header value")
+                       }
+               }
+       }
+       delete(req.Header, "Host")
 
        req.RemoteAddr = c.remoteAddr
        req.TLS = c.tlsState
@@ -648,6 +744,7 @@ func (c *conn) readRequest() (w *response, err error) {
        w = &response{
                conn:          c,
                req:           req,
+               reqBody:       req.Body,
                handlerHeader: make(Header),
                contentLength: -1,
        }
@@ -755,7 +852,7 @@ func (h extraHeader) Write(w *bufio.Writer) {
 }
 
 // writeHeader finalizes the header sent to the client and writes it
-// to cw.res.conn.buf.
+// to cw.res.conn.bufw.
 //
 // p is not written by writeHeader, but is the first chunk of the body
 // that will be written.  It is sniffed for a Content-Type if none is
@@ -821,7 +918,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
        // send a Content-Length header.
        // Further, we don't send an automatic Content-Length if they
        // set a Transfer-Encoding, because they're generally incompatible.
-       if w.handlerDone && !trailers && !hasTE && bodyAllowedForStatus(w.status) && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
+       if w.handlerDone.isSet() && !trailers && !hasTE && bodyAllowedForStatus(w.status) && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
                w.contentLength = int64(len(p))
                setHeader.contentLength = strconv.AppendInt(cw.res.clenBuf[:0], int64(len(p)), 10)
        }
@@ -898,7 +995,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
                }
 
                if discard {
-                       _, err := io.CopyN(ioutil.Discard, w.req.Body, maxPostHandlerReadBytes+1)
+                       _, err := io.CopyN(ioutil.Discard, w.reqBody, maxPostHandlerReadBytes+1)
                        switch err {
                        case nil:
                                // There must be even more data left over.
@@ -907,7 +1004,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
                                // Body was already consumed and closed.
                        case io.EOF:
                                // The remaining body was just consumed, close it.
-                               err = w.req.Body.Close()
+                               err = w.reqBody.Close()
                                if err != nil {
                                        w.closeAfterReply = true
                                }
@@ -996,10 +1093,10 @@ func (cw *chunkWriter) writeHeader(p []byte) {
                }
        }
 
-       w.conn.buf.WriteString(statusLine(w.req, code))
-       cw.header.WriteSubset(w.conn.buf, excludeHeader)
-       setHeader.Write(w.conn.buf.Writer)
-       w.conn.buf.Write(crlf)
+       w.conn.bufw.WriteString(statusLine(w.req, code))
+       cw.header.WriteSubset(w.conn.bufw, excludeHeader)
+       setHeader.Write(w.conn.bufw)
+       w.conn.bufw.Write(crlf)
 }
 
 // foreachHeaderElement splits v according to the "#rule" construction
@@ -1144,7 +1241,7 @@ func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err er
 }
 
 func (w *response) finishRequest() {
-       w.handlerDone = true
+       w.handlerDone.setTrue()
 
        if !w.wroteHeader {
                w.WriteHeader(StatusOK)
@@ -1153,11 +1250,11 @@ func (w *response) finishRequest() {
        w.w.Flush()
        putBufioWriter(w.w)
        w.cw.close()
-       w.conn.buf.Flush()
+       w.conn.bufw.Flush()
 
        // Close the body (regardless of w.closeAfterReply) so we can
        // re-use its bufio.Reader later safely.
-       w.req.Body.Close()
+       w.reqBody.Close()
 
        if w.req.MultipartForm != nil {
                w.req.MultipartForm.RemoveAll()
@@ -1206,28 +1303,26 @@ func (w *response) Flush() {
 }
 
 func (c *conn) finalFlush() {
-       if c.buf != nil {
-               c.buf.Flush()
-
+       if c.bufr != nil {
                // Steal the bufio.Reader (~4KB worth of memory) and its associated
                // reader for a future connection.
-               putBufioReader(c.buf.Reader)
+               putBufioReader(c.bufr)
+               c.bufr = nil
+       }
 
+       if c.bufw != nil {
+               c.bufw.Flush()
                // Steal the bufio.Writer (~4KB worth of memory) and its associated
                // writer for a future connection.
-               putBufioWriter(c.buf.Writer)
-
-               c.buf = nil
+               putBufioWriter(c.bufw)
+               c.bufw = nil
        }
 }
 
 // Close the connection.
 func (c *conn) close() {
        c.finalFlush()
-       if c.rwc != nil {
-               c.rwc.Close()
-               c.rwc = nil
-       }
+       c.rwc.Close()
 }
 
 // rstAvoidanceDelay is the amount of time we sleep after closing the
@@ -1277,9 +1372,16 @@ func (c *conn) setState(nc net.Conn, state ConnState) {
        }
 }
 
+// badRequestError is a literal string (used by in the server in HTML,
+// unescaped) to tell the user why their request was bad. It should
+// be plain text without user info or other embeddded errors.
+type badRequestError string
+
+func (e badRequestError) Error() string { return "Bad Request: " + string(e) }
+
 // Serve a new connection.
 func (c *conn) serve() {
-       origConn := c.rwc // copy it before it's set nil on Close or Hijack
+       c.remoteAddr = c.rwc.RemoteAddr().String()
        defer func() {
                if err := recover(); err != nil {
                        const size = 64 << 10
@@ -1289,7 +1391,7 @@ func (c *conn) serve() {
                }
                if !c.hijacked() {
                        c.close()
-                       c.setState(origConn, StateClosed)
+                       c.setState(c.rwc, StateClosed)
                }
        }()
 
@@ -1315,9 +1417,13 @@ func (c *conn) serve() {
                }
        }
 
+       c.r = &connReader{r: c.rwc}
+       c.bufr = newBufioReader(c.r)
+       c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)
+
        for {
                w, err := c.readRequest()
-               if c.lr.N != c.server.initialLimitedReaderSize() {
+               if c.r.remain != c.server.initialReadLimitSize() {
                        // If we read any bytes off the wire, we're active.
                        c.setState(c.rwc, StateActive)
                }
@@ -1328,16 +1434,22 @@ func (c *conn) serve() {
                                // responding to them and hanging up
                                // while they're still writing their
                                // request.  Undefined behavior.
-                               io.WriteString(c.rwc, "HTTP/1.1 413 Request Entity Too Large\r\n\r\n")
+                               io.WriteString(c.rwc, "HTTP/1.1 431 Request Header Fields Too Large\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n431 Request Header Fields Too Large")
                                c.closeWriteAndWait()
-                               break
-                       } else if err == io.EOF {
-                               break // Don't reply
-                       } else if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
-                               break // Don't reply
+                               return
                        }
-                       io.WriteString(c.rwc, "HTTP/1.1 400 Bad Request\r\n\r\n")
-                       break
+                       if err == io.EOF {
+                               return // don't reply
+                       }
+                       if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
+                               return // don't reply
+                       }
+                       var publicErr string
+                       if v, ok := err.(badRequestError); ok {
+                               publicErr = ": " + string(v)
+                       }
+                       io.WriteString(c.rwc, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n400 Bad Request"+publicErr)
+                       return
                }
 
                // Expect 100 Continue support
@@ -1347,10 +1459,9 @@ func (c *conn) serve() {
                                // Wrap the Body reader with one that replies on the connection
                                req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
                        }
-                       req.Header.Del("Expect")
                } else if req.Header.get("Expect") != "" {
                        w.sendExpectationFailed()
-                       break
+                       return
                }
 
                // HTTP cannot have multiple simultaneous active requests.[*]
@@ -1367,7 +1478,7 @@ func (c *conn) serve() {
                        if w.requestBodyLimitHit || w.closedRequestBodyEarly() {
                                c.closeWriteAndWait()
                        }
-                       break
+                       return
                }
                c.setState(c.rwc, StateIdle)
        }
@@ -1394,12 +1505,24 @@ func (w *response) sendExpectationFailed() {
 // Hijack implements the Hijacker.Hijack method. Our response is both a ResponseWriter
 // and a Hijacker.
 func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
+       if w.handlerDone.isSet() {
+               panic("net/http: Hijack called after ServeHTTP finished")
+       }
        if w.wroteHeader {
                w.cw.flush()
        }
+
+       c := w.conn
+       c.mu.Lock()
+       defer c.mu.Unlock()
+
+       if w.closeNotifyCh != nil {
+               return nil, nil, errors.New("http: Hijack is incompatible with use of CloseNotifier in same ServeHTTP call")
+       }
+
        // Release the bufioWriter that writes to the chunk writer, it is not
        // used after a connection has been hijacked.
-       rwc, buf, err = w.conn.hijack()
+       rwc, buf, err = c.hijackLocked()
        if err == nil {
                putBufioWriter(w.w)
                w.w = nil
@@ -1408,13 +1531,86 @@ func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
 }
 
 func (w *response) CloseNotify() <-chan bool {
-       return w.conn.closeNotify()
+       if w.handlerDone.isSet() {
+               panic("net/http: CloseNotify called after ServeHTTP finished")
+       }
+       c := w.conn
+       c.mu.Lock()
+       defer c.mu.Unlock()
+
+       if w.closeNotifyCh != nil {
+               return w.closeNotifyCh
+       }
+       ch := make(chan bool, 1)
+       w.closeNotifyCh = ch
+
+       if w.conn.hijackedv {
+               // CloseNotify is undefined after a hijack, but we have
+               // no place to return an error, so just return a channel,
+               // even though it'll never receive a value.
+               return ch
+       }
+
+       var once sync.Once
+       notify := func() { once.Do(func() { ch <- true }) }
+
+       if requestBodyRemains(w.reqBody) {
+               // They're still consuming the request body, so we
+               // shouldn't notify yet.
+               registerOnHitEOF(w.reqBody, func() {
+                       c.mu.Lock()
+                       defer c.mu.Unlock()
+                       startCloseNotifyBackgroundRead(c, notify)
+               })
+       } else {
+               startCloseNotifyBackgroundRead(c, notify)
+       }
+       return ch
+}
+
+// c.mu must be held.
+func startCloseNotifyBackgroundRead(c *conn, notify func()) {
+       if c.bufr.Buffered() > 0 {
+               // They've consumed the request body, so anything
+               // remaining is a pipelined request, which we
+               // document as firing on.
+               notify()
+       } else {
+               c.r.startBackgroundRead(notify)
+       }
+}
+
+func registerOnHitEOF(rc io.ReadCloser, fn func()) {
+       switch v := rc.(type) {
+       case *expectContinueReader:
+               registerOnHitEOF(v.readCloser, fn)
+       case *body:
+               v.registerOnHitEOF(fn)
+       default:
+               panic("unexpected type " + fmt.Sprintf("%T", rc))
+       }
+}
+
+// requestBodyRemains reports whether future calls to Read
+// on rc might yield more data.
+func requestBodyRemains(rc io.ReadCloser) bool {
+       if rc == eofReader {
+               return false
+       }
+       switch v := rc.(type) {
+       case *expectContinueReader:
+               return requestBodyRemains(v.readCloser)
+       case *body:
+               return v.bodyRemains()
+       default:
+               panic("unexpected type " + fmt.Sprintf("%T", rc))
+       }
 }
 
 // The HandlerFunc type is an adapter to allow the use of
 // ordinary functions as HTTP handlers.  If f is a function
 // with the appropriate signature, HandlerFunc(f) is a
-// Handler object that calls f.
+// Handler that calls f.
 type HandlerFunc func(ResponseWriter, *Request)
 
 // ServeHTTP calls f(w, r).
@@ -1461,6 +1657,9 @@ func StripPrefix(prefix string, h Handler) Handler {
 
 // Redirect replies to the request with a redirect to url,
 // which may be a path relative to the request path.
+//
+// The provided code should be in the 3xx range and is usually
+// StatusMovedPermanently, StatusFound or StatusSeeOther.
 func Redirect(w ResponseWriter, r *Request, urlStr string, code int) {
        if u, err := url.Parse(urlStr); err == nil {
                // If url was relative, make absolute by
@@ -1479,11 +1678,12 @@ func Redirect(w ResponseWriter, r *Request, urlStr string, code int) {
                // Because of this problem, no one pays attention
                // to the RFC; they all send back just a new path.
                // So do we.
-               oldpath := r.URL.Path
-               if oldpath == "" { // should not happen, but avoid a crash if it does
-                       oldpath = "/"
-               }
-               if u.Scheme == "" {
+               if u.Scheme == "" && u.Host == "" {
+                       oldpath := r.URL.Path
+                       if oldpath == "" { // should not happen, but avoid a crash if it does
+                               oldpath = "/"
+                       }
+
                        // no leading http://server
                        if urlStr == "" || urlStr[0] != '/' {
                                // make relative path absolute
@@ -1545,6 +1745,9 @@ func (rh *redirectHandler) ServeHTTP(w ResponseWriter, r *Request) {
 // RedirectHandler returns a request handler that redirects
 // each request it receives to the given url using the given
 // status code.
+//
+// The provided code should be in the 3xx range and is usually
+// StatusMovedPermanently, StatusFound or StatusSeeOther.
 func RedirectHandler(url string, code int) Handler {
        return &redirectHandler{url, code}
 }
@@ -1567,6 +1770,14 @@ func RedirectHandler(url string, code int) Handler {
 // the pattern "/" matches all paths not matched by other registered
 // patterns, not just the URL with Path == "/".
 //
+// If a subtree has been registered and a request is received naming the
+// subtree root without its trailing slash, ServeMux redirects that
+// request to the subtree root (adding the trailing slash). This behavior can
+// be overridden with a separate registration for the path without
+// the trailing slash. For example, registering "/images/" causes ServeMux
+// to redirect a request for "/images" to "/images/", unless "/images" has
+// been registered separately.
+//
 // Patterns may optionally begin with a host name, restricting matches to
 // URLs on that host only.  Host-specific patterns take precedence over
 // general patterns, so that a handler might register for the two patterns
@@ -1574,8 +1785,8 @@ func RedirectHandler(url string, code int) Handler {
 // requests for "http://www.google.com/".
 //
 // ServeMux also takes care of sanitizing the URL request path,
-// redirecting any request containing . or .. elements to an
-// equivalent .- and ..-free URL.
+// redirecting any request containing . or .. elements or repeated slashes
+// to an equivalent, cleaner URL.
 type ServeMux struct {
        mu    sync.RWMutex
        m     map[string]muxEntry
@@ -1782,6 +1993,7 @@ type Server struct {
        // handle HTTP requests and will initialize the Request's TLS
        // and RemoteAddr if not already set.  The connection is
        // automatically closed when the function returns.
+       // If TLSNextProto is nil, HTTP/2 support is enabled automatically.
        TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
 
        // ConnState specifies an optional callback function that is
@@ -1795,7 +2007,9 @@ type Server struct {
        // standard logger.
        ErrorLog *log.Logger
 
-       disableKeepAlives int32 // accessed atomically.
+       disableKeepAlives int32     // accessed atomically.
+       nextProtoOnce     sync.Once // guards initialization of TLSNextProto in Serve
+       nextProtoErr      error
 }
 
 // A ConnState represents the state of a client connection to a server.
@@ -1815,6 +2029,11 @@ const (
        // and doesn't fire again until the request has been
        // handled. After the request is handled, the state
        // transitions to StateClosed, StateHijacked, or StateIdle.
+       // For HTTP/2, StateActive fires on the transition from zero
+       // to one active request, and only transitions away once all
+       // active requests are complete. That means that ConnState
+       // can not be used to do per-request work; ConnState only notes
+       // the overall state of the connection.
        StateActive
 
        // StateIdle represents a connection that has finished
@@ -1863,8 +2082,10 @@ func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
 }
 
 // ListenAndServe listens on the TCP network address srv.Addr and then
-// calls Serve to handle requests on incoming connections.  If
-// srv.Addr is blank, ":http" is used.
+// calls Serve to handle requests on incoming connections.
+// Accepted connections are configured to enable TCP keep-alives.
+// If srv.Addr is blank, ":http" is used.
+// ListenAndServe always returns a non-nil error.
 func (srv *Server) ListenAndServe() error {
        addr := srv.Addr
        if addr == "" {
@@ -1877,12 +2098,21 @@ func (srv *Server) ListenAndServe() error {
        return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
 }
 
+var testHookServerServe func(*Server, net.Listener) // used if non-nil
+
 // Serve accepts incoming connections on the Listener l, creating a
-// new service goroutine for each.  The service goroutines read requests and
+// new service goroutine for each. The service goroutines read requests and
 // then call srv.Handler to reply to them.
+// Serve always returns a non-nil error.
 func (srv *Server) Serve(l net.Listener) error {
        defer l.Close()
+       if fn := testHookServerServe; fn != nil {
+               fn(srv, l)
+       }
        var tempDelay time.Duration // how long to sleep on accept failure
+       if err := srv.setupHTTP2(); err != nil {
+               return err
+       }
        for {
                rw, e := l.Accept()
                if e != nil {
@@ -1902,10 +2132,7 @@ func (srv *Server) Serve(l net.Listener) error {
                        return e
                }
                tempDelay = 0
-               c, err := srv.newConn(rw)
-               if err != nil {
-                       continue
-               }
+               c := srv.newConn(rw)
                c.setState(c.rwc, StateNew) // before Serve can return
                go c.serve()
        }
@@ -1937,8 +2164,10 @@ func (s *Server) logf(format string, args ...interface{}) {
 
 // ListenAndServe listens on the TCP network address addr
 // and then calls Serve with handler to handle requests
-// on incoming connections.  Handler is typically nil,
-// in which case the DefaultServeMux is used.
+// on incoming connections.
+// Accepted connections are configured to enable TCP keep-alives.
+// Handler is typically nil, in which case the DefaultServeMux is
+// used.
 //
 // A trivial example server is:
 //
@@ -1957,11 +2186,10 @@ func (s *Server) logf(format string, args ...interface{}) {
 //
 //     func main() {
 //             http.HandleFunc("/hello", HelloServer)
-//             err := http.ListenAndServe(":12345", nil)
-//             if err != nil {
-//                     log.Fatal("ListenAndServe: ", err)
-//             }
+//             log.Fatal(http.ListenAndServe(":12345", nil))
 //     }
+//
+// ListenAndServe always returns a non-nil error.
 func ListenAndServe(addr string, handler Handler) error {
        server := &Server{Addr: addr, Handler: handler}
        return server.ListenAndServe()
@@ -1989,19 +2217,20 @@ func ListenAndServe(addr string, handler Handler) error {
 //             http.HandleFunc("/", handler)
 //             log.Printf("About to listen on 10443. Go to https://127.0.0.1:10443/")
 //             err := http.ListenAndServeTLS(":10443", "cert.pem", "key.pem", nil)
-//             if err != nil {
-//                     log.Fatal(err)
-//             }
+//             log.Fatal(err)
 //     }
 //
 // One can use generate_cert.go in crypto/tls to generate cert.pem and key.pem.
-func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) error {
+//
+// ListenAndServeTLS always returns a non-nil error.
+func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error {
        server := &Server{Addr: addr, Handler: handler}
        return server.ListenAndServeTLS(certFile, keyFile)
 }
 
 // ListenAndServeTLS listens on the TCP network address srv.Addr and
 // then calls Serve to handle requests on incoming TLS connections.
+// Accepted connections are configured to enable TCP keep-alives.
 //
 // Filenames containing a certificate and matching private key for the
 // server must be provided if the Server's TLSConfig.Certificates is
@@ -2010,14 +2239,23 @@ func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Han
 // certificate, any intermediates, and the CA's certificate.
 //
 // If srv.Addr is blank, ":https" is used.
+//
+// ListenAndServeTLS always returns a non-nil error.
 func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
        addr := srv.Addr
        if addr == "" {
                addr = ":https"
        }
+
+       // Setup HTTP/2 before srv.Serve, to initialize srv.TLSConfig
+       // before we clone it and create the TLS Listener.
+       if err := srv.setupHTTP2(); err != nil {
+               return err
+       }
+
        config := cloneTLSConfig(srv.TLSConfig)
-       if config.NextProtos == nil {
-               config.NextProtos = []string{"http/1.1"}
+       if !strSliceContains(config.NextProtos, "http/1.1") {
+               config.NextProtos = append(config.NextProtos, "http/1.1")
        }
 
        if len(config.Certificates) == 0 || certFile != "" || keyFile != "" {
@@ -2038,6 +2276,25 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
        return srv.Serve(tlsListener)
 }
 
+func (srv *Server) setupHTTP2() error {
+       srv.nextProtoOnce.Do(srv.onceSetNextProtoDefaults)
+       return srv.nextProtoErr
+}
+
+// onceSetNextProtoDefaults configures HTTP/2, if the user hasn't
+// configured otherwise. (by setting srv.TLSNextProto non-nil)
+// It must only be called via srv.nextProtoOnce (use srv.setupHTTP2).
+func (srv *Server) onceSetNextProtoDefaults() {
+       if strings.Contains(os.Getenv("GODEBUG"), "http2server=0") {
+               return
+       }
+       // Enable HTTP/2 by default if the user hasn't otherwise
+       // configured their TLSNextProto map.
+       if srv.TLSNextProto == nil {
+               srv.nextProtoErr = http2ConfigureServer(srv, nil)
+       }
+}
+
 // TimeoutHandler returns a Handler that runs h with the given time limit.
 //
 // The new Handler calls h.ServeHTTP to handle each request, but if a
@@ -2046,11 +2303,20 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
 // (If msg is empty, a suitable default message will be sent.)
 // After such a timeout, writes by h to its ResponseWriter will return
 // ErrHandlerTimeout.
+//
+// TimeoutHandler buffers all Handler writes to memory and does not
+// support the Hijacker or Flusher interfaces.
 func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler {
-       f := func() <-chan time.Time {
-               return time.After(dt)
+       t := time.NewTimer(dt)
+       return &timeoutHandler{
+               handler: h,
+               body:    msg,
+
+               // Effectively storing a *time.Timer, but decomposed
+               // for testing:
+               timeout:     func() <-chan time.Time { return t.C },
+               cancelTimer: t.Stop,
        }
-       return &timeoutHandler{h, f, msg}
 }
 
 // ErrHandlerTimeout is returned on ResponseWriter Write calls
@@ -2059,8 +2325,13 @@ var ErrHandlerTimeout = errors.New("http: Handler timeout")
 
 type timeoutHandler struct {
        handler Handler
-       timeout func() <-chan time.Time // returns channel producing a timeout
        body    string
+
+       // timeout returns the channel of a *time.Timer and
+       // cancelTimer cancels it.  They're stored separately for
+       // testing purposes.
+       timeout     func() <-chan time.Time // returns channel producing a timeout
+       cancelTimer func() bool             // optional
 }
 
 func (h *timeoutHandler) errorBody() string {
@@ -2071,46 +2342,61 @@ func (h *timeoutHandler) errorBody() string {
 }
 
 func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) {
-       done := make(chan bool, 1)
-       tw := &timeoutWriter{w: w}
+       done := make(chan struct{})
+       tw := &timeoutWriter{
+               w: w,
+               h: make(Header),
+       }
        go func() {
                h.handler.ServeHTTP(tw, r)
-               done <- true
+               close(done)
        }()
        select {
        case <-done:
-               return
-       case <-h.timeout():
                tw.mu.Lock()
                defer tw.mu.Unlock()
-               if !tw.wroteHeader {
-                       tw.w.WriteHeader(StatusServiceUnavailable)
-                       tw.w.Write([]byte(h.errorBody()))
+               dst := w.Header()
+               for k, vv := range tw.h {
+                       dst[k] = vv
+               }
+               w.WriteHeader(tw.code)
+               w.Write(tw.wbuf.Bytes())
+               if h.cancelTimer != nil {
+                       h.cancelTimer()
                }
+       case <-h.timeout():
+               tw.mu.Lock()
+               defer tw.mu.Unlock()
+               w.WriteHeader(StatusServiceUnavailable)
+               io.WriteString(w, h.errorBody())
                tw.timedOut = true
+               return
        }
 }
 
 type timeoutWriter struct {
-       w ResponseWriter
+       w    ResponseWriter
+       h    Header
+       wbuf bytes.Buffer
 
        mu          sync.Mutex
        timedOut    bool
        wroteHeader bool
+       code        int
 }
 
-func (tw *timeoutWriter) Header() Header {
-       return tw.w.Header()
-}
+func (tw *timeoutWriter) Header() Header { return tw.h }
 
 func (tw *timeoutWriter) Write(p []byte) (int, error) {
        tw.mu.Lock()
        defer tw.mu.Unlock()
-       tw.wroteHeader = true // implicitly at least
        if tw.timedOut {
                return 0, ErrHandlerTimeout
        }
-       return tw.w.Write(p)
+       if !tw.wroteHeader {
+               tw.writeHeader(StatusOK)
+       }
+       return tw.wbuf.Write(p)
 }
 
 func (tw *timeoutWriter) WriteHeader(code int) {
@@ -2119,8 +2405,12 @@ func (tw *timeoutWriter) WriteHeader(code int) {
        if tw.timedOut || tw.wroteHeader {
                return
        }
+       tw.writeHeader(code)
+}
+
+func (tw *timeoutWriter) writeHeader(code int) {
        tw.wroteHeader = true
-       tw.w.WriteHeader(code)
+       tw.code = code
 }
 
 // tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
@@ -2247,7 +2537,7 @@ type checkConnErrorWriter struct {
 }
 
 func (w checkConnErrorWriter) Write(p []byte) (n int, err error) {
-       n, err = w.c.w.Write(p) // c.w == c.rwc, except after a hijack, when rwc is nil.
+       n, err = w.c.rwc.Write(p)
        if err != nil && w.c.werr == nil {
                w.c.werr = err
        }
@@ -2265,3 +2555,12 @@ func numLeadingCRorLF(v []byte) (n int) {
        return
 
 }
+
+func strSliceContains(ss []string, s string) bool {
+       for _, v := range ss {
+               if v == s {
+                       return true
+               }
+       }
+       return false
+}
index 3be8c865d3b3933c18ecfa456ec99b322d1b9bdd..18810bad068a2c6244777f93be904fe4fc27c87b 100644 (file)
@@ -102,10 +102,9 @@ var sniffSignatures = []sniffSig{
        &exactSig{[]byte("\x50\x4B\x03\x04"), "application/zip"},
        &exactSig{[]byte("\x1F\x8B\x08"), "application/x-gzip"},
 
-       // TODO(dsymonds): Re-enable this when the spec is sorted w.r.t. MP4.
-       //mp4Sig(0),
+       mp4Sig{},
 
-       textSig(0), // should be last
+       textSig{}, // should be last
 }
 
 type exactSig struct {
@@ -166,12 +165,14 @@ func (h htmlSig) match(data []byte, firstNonWS int) string {
 }
 
 var mp4ftype = []byte("ftyp")
+var mp4 = []byte("mp4")
 
-type mp4Sig int
+type mp4Sig struct{}
 
 func (mp4Sig) match(data []byte, firstNonWS int) string {
-       // c.f. section 6.1.
-       if len(data) < 8 {
+       // https://mimesniff.spec.whatwg.org/#signature-for-mp4
+       // c.f. section 6.2.1
+       if len(data) < 12 {
                return ""
        }
        boxSize := int(binary.BigEndian.Uint32(data[:4]))
@@ -186,30 +187,20 @@ func (mp4Sig) match(data []byte, firstNonWS int) string {
                        // minor version number
                        continue
                }
-               seg := string(data[st : st+3])
-               switch seg {
-               case "mp4", "iso", "M4V", "M4P", "M4B":
+               if bytes.Equal(data[st:st+3], mp4) {
                        return "video/mp4"
-                       /* The remainder are not in the spec.
-                       case "M4A":
-                               return "audio/mp4"
-                       case "3gp":
-                               return "video/3gpp"
-                       case "jp2":
-                               return "image/jp2" // JPEG 2000
-                       */
                }
        }
        return ""
 }
 
-type textSig int
+type textSig struct{}
 
 func (textSig) match(data []byte, firstNonWS int) string {
        // c.f. section 5, step 4.
        for _, b := range data[firstNonWS:] {
                switch {
-               case 0x00 <= b && b <= 0x08,
+               case b <= 0x08,
                        b == 0x0B,
                        0x0E <= b && b <= 0x1A,
                        0x1C <= b && b <= 0x1F:
index 24ca27afc16745c82362cfa7ea6a46e84ea5a72a..e0085516da31ab6e04dbc06807d5df994471d154 100644 (file)
@@ -11,7 +11,6 @@ import (
        "io/ioutil"
        "log"
        . "net/http"
-       "net/http/httptest"
        "reflect"
        "strconv"
        "strings"
@@ -40,9 +39,7 @@ var sniffTests = []struct {
        {"GIF 87a", []byte(`GIF87a`), "image/gif"},
        {"GIF 89a", []byte(`GIF89a...`), "image/gif"},
 
-       // TODO(dsymonds): Re-enable this when the spec is sorted w.r.t. MP4.
-       //{"MP4 video", []byte("\x00\x00\x00\x18ftypmp42\x00\x00\x00\x00mp42isom<\x06t\xbfmdat"), "video/mp4"},
-       //{"MP4 audio", []byte("\x00\x00\x00\x20ftypM4A \x00\x00\x00\x00M4A mp42isom\x00\x00\x00\x00"), "audio/mp4"},
+       {"MP4 video", []byte("\x00\x00\x00\x18ftypmp42\x00\x00\x00\x00mp42isom<\x06t\xbfmdat"), "video/mp4"},
 }
 
 func TestDetectContentType(t *testing.T) {
@@ -54,9 +51,12 @@ func TestDetectContentType(t *testing.T) {
        }
 }
 
-func TestServerContentType(t *testing.T) {
+func TestServerContentType_h1(t *testing.T) { testServerContentType(t, h1Mode) }
+func TestServerContentType_h2(t *testing.T) { testServerContentType(t, h2Mode) }
+
+func testServerContentType(t *testing.T, h2 bool) {
        defer afterTest(t)
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
                i, _ := strconv.Atoi(r.FormValue("i"))
                tt := sniffTests[i]
                n, err := w.Write(tt.data)
@@ -64,10 +64,10 @@ func TestServerContentType(t *testing.T) {
                        log.Fatalf("%v: Write(%q) = %v, %v want %d, nil", tt.desc, tt.data, n, err, len(tt.data))
                }
        }))
-       defer ts.Close()
+       defer cst.close()
 
        for i, tt := range sniffTests {
-               resp, err := Get(ts.URL + "/?i=" + strconv.Itoa(i))
+               resp, err := cst.c.Get(cst.ts.URL + "/?i=" + strconv.Itoa(i))
                if err != nil {
                        t.Errorf("%v: %v", tt.desc, err)
                        continue
@@ -87,15 +87,17 @@ func TestServerContentType(t *testing.T) {
 
 // Issue 5953: shouldn't sniff if the handler set a Content-Type header,
 // even if it's the empty string.
-func TestServerIssue5953(t *testing.T) {
+func TestServerIssue5953_h1(t *testing.T) { testServerIssue5953(t, h1Mode) }
+func TestServerIssue5953_h2(t *testing.T) { testServerIssue5953(t, h2Mode) }
+func testServerIssue5953(t *testing.T, h2 bool) {
        defer afterTest(t)
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
                w.Header()["Content-Type"] = []string{""}
                fmt.Fprintf(w, "<html><head></head><body>hi</body></html>")
        }))
-       defer ts.Close()
+       defer cst.close()
 
-       resp, err := Get(ts.URL)
+       resp, err := cst.c.Get(cst.ts.URL)
        if err != nil {
                t.Fatal(err)
        }
@@ -108,7 +110,9 @@ func TestServerIssue5953(t *testing.T) {
        resp.Body.Close()
 }
 
-func TestContentTypeWithCopy(t *testing.T) {
+func TestContentTypeWithCopy_h1(t *testing.T) { testContentTypeWithCopy(t, h1Mode) }
+func TestContentTypeWithCopy_h2(t *testing.T) { testContentTypeWithCopy(t, h2Mode) }
+func testContentTypeWithCopy(t *testing.T, h2 bool) {
        defer afterTest(t)
 
        const (
@@ -116,7 +120,7 @@ func TestContentTypeWithCopy(t *testing.T) {
                expected = "text/html; charset=utf-8"
        )
 
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
                // Use io.Copy from a bytes.Buffer to trigger ReadFrom.
                buf := bytes.NewBuffer([]byte(input))
                n, err := io.Copy(w, buf)
@@ -124,9 +128,9 @@ func TestContentTypeWithCopy(t *testing.T) {
                        t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input))
                }
        }))
-       defer ts.Close()
+       defer cst.close()
 
-       resp, err := Get(ts.URL)
+       resp, err := cst.c.Get(cst.ts.URL)
        if err != nil {
                t.Fatalf("Get: %v", err)
        }
@@ -142,9 +146,11 @@ func TestContentTypeWithCopy(t *testing.T) {
        resp.Body.Close()
 }
 
-func TestSniffWriteSize(t *testing.T) {
+func TestSniffWriteSize_h1(t *testing.T) { testSniffWriteSize(t, h1Mode) }
+func TestSniffWriteSize_h2(t *testing.T) { testSniffWriteSize(t, h2Mode) }
+func testSniffWriteSize(t *testing.T, h2 bool) {
        defer afterTest(t)
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
                size, _ := strconv.Atoi(r.FormValue("size"))
                written, err := io.WriteString(w, strings.Repeat("a", size))
                if err != nil {
@@ -155,9 +161,9 @@ func TestSniffWriteSize(t *testing.T) {
                        t.Errorf("write of %d bytes wrote %d bytes", size, written)
                }
        }))
-       defer ts.Close()
+       defer cst.close()
        for _, size := range []int{0, 1, 200, 600, 999, 1000, 1023, 1024, 512 << 10, 1 << 20} {
-               res, err := Get(fmt.Sprintf("%s/?size=%d", ts.URL, size))
+               res, err := cst.c.Get(fmt.Sprintf("%s/?size=%d", cst.ts.URL, size))
                if err != nil {
                        t.Fatalf("size %d: %v", size, err)
                }
index d253bd5cb54d49aacdb029a23f574b23a1de7b28..f3dacab6a92043bf0ffa12515a384e7ed5cc5479 100644 (file)
@@ -44,20 +44,18 @@ const (
        StatusRequestedRangeNotSatisfiable = 416
        StatusExpectationFailed            = 417
        StatusTeapot                       = 418
+       StatusPreconditionRequired         = 428
+       StatusTooManyRequests              = 429
+       StatusRequestHeaderFieldsTooLarge  = 431
+       StatusUnavailableForLegalReasons   = 451
 
-       StatusInternalServerError     = 500
-       StatusNotImplemented          = 501
-       StatusBadGateway              = 502
-       StatusServiceUnavailable      = 503
-       StatusGatewayTimeout          = 504
-       StatusHTTPVersionNotSupported = 505
-
-       // New HTTP status codes from RFC 6585. Not exported yet in Go 1.1.
-       // See discussion at https://codereview.appspot.com/7678043/
-       statusPreconditionRequired          = 428
-       statusTooManyRequests               = 429
-       statusRequestHeaderFieldsTooLarge   = 431
-       statusNetworkAuthenticationRequired = 511
+       StatusInternalServerError           = 500
+       StatusNotImplemented                = 501
+       StatusBadGateway                    = 502
+       StatusServiceUnavailable            = 503
+       StatusGatewayTimeout                = 504
+       StatusHTTPVersionNotSupported       = 505
+       StatusNetworkAuthenticationRequired = 511
 )
 
 var statusText = map[int]string{
@@ -99,18 +97,18 @@ var statusText = map[int]string{
        StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
        StatusExpectationFailed:            "Expectation Failed",
        StatusTeapot:                       "I'm a teapot",
+       StatusPreconditionRequired:         "Precondition Required",
+       StatusTooManyRequests:              "Too Many Requests",
+       StatusRequestHeaderFieldsTooLarge:  "Request Header Fields Too Large",
+       StatusUnavailableForLegalReasons:   "Unavailable For Legal Reasons",
 
-       StatusInternalServerError:     "Internal Server Error",
-       StatusNotImplemented:          "Not Implemented",
-       StatusBadGateway:              "Bad Gateway",
-       StatusServiceUnavailable:      "Service Unavailable",
-       StatusGatewayTimeout:          "Gateway Timeout",
-       StatusHTTPVersionNotSupported: "HTTP Version Not Supported",
-
-       statusPreconditionRequired:          "Precondition Required",
-       statusTooManyRequests:               "Too Many Requests",
-       statusRequestHeaderFieldsTooLarge:   "Request Header Fields Too Large",
-       statusNetworkAuthenticationRequired: "Network Authentication Required",
+       StatusInternalServerError:           "Internal Server Error",
+       StatusNotImplemented:                "Not Implemented",
+       StatusBadGateway:                    "Bad Gateway",
+       StatusServiceUnavailable:            "Service Unavailable",
+       StatusGatewayTimeout:                "Gateway Timeout",
+       StatusHTTPVersionNotSupported:       "HTTP Version Not Supported",
+       StatusNetworkAuthenticationRequired: "Network Authentication Required",
 }
 
 // StatusText returns a text for the HTTP status code. It returns the empty
index a8736b28e16106b6640ec0ffdb1d2392e7e43552..6e59af8f6f4fe9ab00cd813fc360c4f03121987f 100644 (file)
@@ -56,7 +56,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
                if rr.ContentLength != 0 && rr.Body == nil {
                        return nil, fmt.Errorf("http: Request.ContentLength=%d with nil Body", rr.ContentLength)
                }
-               t.Method = rr.Method
+               t.Method = valueOrDefault(rr.Method, "GET")
                t.Body = rr.Body
                t.BodyCloser = rr.Body
                t.ContentLength = rr.ContentLength
@@ -271,6 +271,10 @@ type transferReader struct {
        Trailer          Header
 }
 
+func (t *transferReader) protoAtLeast(m, n int) bool {
+       return t.ProtoMajor > m || (t.ProtoMajor == m && t.ProtoMinor >= n)
+}
+
 // bodyAllowedForStatus reports whether a given response status code
 // permits a body.  See RFC2616, section 4.4.
 func bodyAllowedForStatus(status int) bool {
@@ -337,7 +341,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
        }
 
        // Transfer encoding, content length
-       t.TransferEncoding, err = fixTransferEncoding(isResponse, t.RequestMethod, t.Header)
+       err = t.fixTransferEncoding()
        if err != nil {
                return err
        }
@@ -424,13 +428,18 @@ func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }
 // Checks whether the encoding is explicitly "identity".
 func isIdentity(te []string) bool { return len(te) == 1 && te[0] == "identity" }
 
-// Sanitize transfer encoding
-func fixTransferEncoding(isResponse bool, requestMethod string, header Header) ([]string, error) {
-       raw, present := header["Transfer-Encoding"]
+// fixTransferEncoding sanitizes t.TransferEncoding, if needed.
+func (t *transferReader) fixTransferEncoding() error {
+       raw, present := t.Header["Transfer-Encoding"]
        if !present {
-               return nil, nil
+               return nil
+       }
+       delete(t.Header, "Transfer-Encoding")
+
+       // Issue 12785; ignore Transfer-Encoding on HTTP/1.0 requests.
+       if !t.protoAtLeast(1, 1) {
+               return nil
        }
-       delete(header, "Transfer-Encoding")
 
        encodings := strings.Split(raw[0], ",")
        te := make([]string, 0, len(encodings))
@@ -445,13 +454,13 @@ func fixTransferEncoding(isResponse bool, requestMethod string, header Header) (
                        break
                }
                if encoding != "chunked" {
-                       return nil, &badStringError{"unsupported transfer encoding", encoding}
+                       return &badStringError{"unsupported transfer encoding", encoding}
                }
                te = te[0 : len(te)+1]
                te[len(te)-1] = encoding
        }
        if len(te) > 1 {
-               return nil, &badStringError{"too many transfer encodings", strings.Join(te, ",")}
+               return &badStringError{"too many transfer encodings", strings.Join(te, ",")}
        }
        if len(te) > 0 {
                // RFC 7230 3.3.2 says "A sender MUST NOT send a
@@ -470,11 +479,12 @@ func fixTransferEncoding(isResponse bool, requestMethod string, header Header) (
                // such a message downstream."
                //
                // Reportedly, these appear in the wild.
-               delete(header, "Content-Length")
-               return te, nil
+               delete(t.Header, "Content-Length")
+               t.TransferEncoding = te
+               return nil
        }
 
-       return nil, nil
+       return nil
 }
 
 // Determine the expected body length, using RFC 2616 Section 4.4. This
@@ -567,21 +577,29 @@ func shouldClose(major, minor int, header Header, removeCloseHeader bool) bool {
 
 // Parse the trailer header
 func fixTrailer(header Header, te []string) (Header, error) {
-       raw := header.get("Trailer")
-       if raw == "" {
+       vv, ok := header["Trailer"]
+       if !ok {
                return nil, nil
        }
-
        header.Del("Trailer")
+
        trailer := make(Header)
-       keys := strings.Split(raw, ",")
-       for _, key := range keys {
-               key = CanonicalHeaderKey(strings.TrimSpace(key))
-               switch key {
-               case "Transfer-Encoding", "Trailer", "Content-Length":
-                       return nil, &badStringError{"bad trailer key", key}
-               }
-               trailer[key] = nil
+       var err error
+       for _, v := range vv {
+               foreachHeaderElement(v, func(key string) {
+                       key = CanonicalHeaderKey(key)
+                       switch key {
+                       case "Transfer-Encoding", "Trailer", "Content-Length":
+                               if err == nil {
+                                       err = &badStringError{"bad trailer key", key}
+                                       return
+                               }
+                       }
+                       trailer[key] = nil
+               })
+       }
+       if err != nil {
+               return nil, err
        }
        if len(trailer) == 0 {
                return nil, nil
@@ -603,10 +621,11 @@ type body struct {
        closing      bool          // is the connection to be closed after reading body?
        doEarlyClose bool          // whether Close should stop early
 
-       mu         sync.Mutex // guards closed, and calls to Read and Close
+       mu         sync.Mutex // guards following, and calls to Read and Close
        sawEOF     bool
        closed     bool
-       earlyClose bool // Close called and we didn't read to the end of src
+       earlyClose bool   // Close called and we didn't read to the end of src
+       onHitEOF   func() // if non-nil, func to call when EOF is Read
 }
 
 // ErrBodyReadAfterClose is returned when reading a Request or Response
@@ -666,6 +685,10 @@ func (b *body) readLocked(p []byte) (n int, err error) {
                }
        }
 
+       if b.sawEOF && b.onHitEOF != nil {
+               b.onHitEOF()
+       }
+
        return n, err
 }
 
@@ -800,6 +823,20 @@ func (b *body) didEarlyClose() bool {
        return b.earlyClose
 }
 
+// bodyRemains reports whether future Read calls might
+// yield data.
+func (b *body) bodyRemains() bool {
+       b.mu.Lock()
+       defer b.mu.Unlock()
+       return !b.sawEOF
+}
+
+func (b *body) registerOnHitEOF(fn func()) {
+       b.mu.Lock()
+       defer b.mu.Unlock()
+       b.onHitEOF = fn
+}
+
 // bodyLocked is a io.Reader reading from a *body when its mutex is
 // already held.
 type bodyLocked struct {
index 70d1864605993f5a46ab908251da112581d070ed..41df906cf2d1d70d3fa1d714ebc4b706f0c692ef 100644 (file)
@@ -36,7 +36,8 @@ var DefaultTransport RoundTripper = &Transport{
                Timeout:   30 * time.Second,
                KeepAlive: 30 * time.Second,
        }).Dial,
-       TLSHandshakeTimeout: 10 * time.Second,
+       TLSHandshakeTimeout:   10 * time.Second,
+       ExpectContinueTimeout: 1 * time.Second,
 }
 
 // DefaultMaxIdleConnsPerHost is the default value of Transport's
@@ -45,7 +46,21 @@ const DefaultMaxIdleConnsPerHost = 2
 
 // Transport is an implementation of RoundTripper that supports HTTP,
 // HTTPS, and HTTP proxies (for either HTTP or HTTPS with CONNECT).
-// Transport can also cache connections for future re-use.
+//
+// By default, Transport caches connections for future re-use.
+// This may leave many open connections when accessing many hosts.
+// This behavior can be managed using Transport's CloseIdleConnections method
+// and the MaxIdleConnsPerHost and DisableKeepAlives fields.
+//
+// Transports should be reused instead of created as needed.
+// Transports are safe for concurrent use by multiple goroutines.
+//
+// A Transport is a low-level primitive for making HTTP and HTTPS requests.
+// For high-level functionality, such as cookies and redirects, see Client.
+//
+// Transport uses HTTP/1.1 for HTTP URLs and either HTTP/1.1 or HTTP/2
+// for HTTPS URLs, depending on whether the server supports HTTP/2.
+// See the package docs for more about HTTP/2.
 type Transport struct {
        idleMu     sync.Mutex
        wantIdle   bool // user has requested to close all idle conns
@@ -113,8 +128,49 @@ type Transport struct {
        // time does not include the time to read the response body.
        ResponseHeaderTimeout time.Duration
 
+       // ExpectContinueTimeout, if non-zero, specifies the amount of
+       // time to wait for a server's first response headers after fully
+       // writing the request headers if the request has an
+       // "Expect: 100-continue" header. Zero means no timeout.
+       // This time does not include the time to send the request header.
+       ExpectContinueTimeout time.Duration
+
+       // TLSNextProto specifies how the Transport switches to an
+       // alternate protocol (such as HTTP/2) after a TLS NPN/ALPN
+       // protocol negotiation.  If Transport dials an TLS connection
+       // with a non-empty protocol name and TLSNextProto contains a
+       // map entry for that key (such as "h2"), then the func is
+       // called with the request's authority (such as "example.com"
+       // or "example.com:1234") and the TLS connection. The function
+       // must return a RoundTripper that then handles the request.
+       // If TLSNextProto is nil, HTTP/2 support is enabled automatically.
+       TLSNextProto map[string]func(authority string, c *tls.Conn) RoundTripper
+
+       // nextProtoOnce guards initialization of TLSNextProto and
+       // h2transport (via onceSetNextProtoDefaults)
+       nextProtoOnce sync.Once
+       h2transport   *http2Transport // non-nil if http2 wired up
+
        // TODO: tunable on global max cached connections
        // TODO: tunable on timeout on cached connections
+       // TODO: tunable on max per-host TCP dials in flight (Issue 13957)
+}
+
+// onceSetNextProtoDefaults initializes TLSNextProto.
+// It must be called via t.nextProtoOnce.Do.
+func (t *Transport) onceSetNextProtoDefaults() {
+       if strings.Contains(os.Getenv("GODEBUG"), "http2client=0") {
+               return
+       }
+       if t.TLSNextProto != nil {
+               return
+       }
+       t2, err := http2configureTransport(t)
+       if err != nil {
+               log.Printf("Error enabling Transport HTTP/2 support: %v", err)
+       } else {
+               t.h2transport = t2
+       }
 }
 
 // ProxyFromEnvironment returns the URL of the proxy to use for a
@@ -188,7 +244,8 @@ func (tr *transportRequest) extraHeaders() Header {
 //
 // For higher-level HTTP client support (such as handling of cookies
 // and redirects), see Get, Post, and the Client type.
-func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) {
+func (t *Transport) RoundTrip(req *Request) (*Response, error) {
+       t.nextProtoOnce.Do(t.onceSetNextProtoDefaults)
        if req.URL == nil {
                req.closeBody()
                return nil, errors.New("http: nil Request.URL")
@@ -197,54 +254,114 @@ func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) {
                req.closeBody()
                return nil, errors.New("http: nil Request.Header")
        }
-       if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
-               t.altMu.RLock()
-               var rt RoundTripper
-               if t.altProto != nil {
-                       rt = t.altProto[req.URL.Scheme]
-               }
-               t.altMu.RUnlock()
-               if rt == nil {
-                       req.closeBody()
-                       return nil, &badStringError{"unsupported protocol scheme", req.URL.Scheme}
+       // TODO(bradfitz): switch to atomic.Value for this map instead of RWMutex
+       t.altMu.RLock()
+       altRT := t.altProto[req.URL.Scheme]
+       t.altMu.RUnlock()
+       if altRT != nil {
+               if resp, err := altRT.RoundTrip(req); err != ErrSkipAltProtocol {
+                       return resp, err
                }
-               return rt.RoundTrip(req)
        }
-       if req.URL.Host == "" {
+       if s := req.URL.Scheme; s != "http" && s != "https" {
                req.closeBody()
-               return nil, errors.New("http: no Host in request URL")
+               return nil, &badStringError{"unsupported protocol scheme", s}
        }
-       treq := &transportRequest{Request: req}
-       cm, err := t.connectMethodForRequest(treq)
-       if err != nil {
+       if req.Method != "" && !validMethod(req.Method) {
+               return nil, fmt.Errorf("net/http: invalid method %q", req.Method)
+       }
+       if req.URL.Host == "" {
                req.closeBody()
-               return nil, err
+               return nil, errors.New("http: no Host in request URL")
        }
 
-       // Get the cached or newly-created connection to either the
-       // 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(req, cm)
-       if err != nil {
-               t.setReqCanceler(req, nil)
-               req.closeBody()
-               return nil, err
+       for {
+               // treq gets modified by roundTrip, so we need to recreate for each retry.
+               treq := &transportRequest{Request: req}
+               cm, err := t.connectMethodForRequest(treq)
+               if err != nil {
+                       req.closeBody()
+                       return nil, err
+               }
+
+               // Get the cached or newly-created connection to either the
+               // 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(req, cm)
+               if err != nil {
+                       t.setReqCanceler(req, nil)
+                       req.closeBody()
+                       return nil, err
+               }
+
+               var resp *Response
+               if pconn.alt != nil {
+                       // HTTP/2 path.
+                       t.setReqCanceler(req, nil) // not cancelable with CancelRequest
+                       resp, err = pconn.alt.RoundTrip(req)
+               } else {
+                       resp, err = pconn.roundTrip(treq)
+               }
+               if err == nil {
+                       return resp, nil
+               }
+               if err := checkTransportResend(err, req, pconn); err != nil {
+                       return nil, err
+               }
+               testHookRoundTripRetried()
        }
+}
 
-       return pconn.roundTrip(treq)
+// checkTransportResend checks whether a failed HTTP request can be
+// resent on a new connection. The non-nil input error is the error from
+// roundTrip, which might be wrapped in a beforeRespHeaderError error.
+//
+// The return value is err or the unwrapped error inside a
+// beforeRespHeaderError.
+func checkTransportResend(err error, req *Request, pconn *persistConn) error {
+       brhErr, ok := err.(beforeRespHeaderError)
+       if !ok {
+               return err
+       }
+       err = brhErr.error // unwrap the custom error in case we return it
+       if err != errMissingHost && pconn.isReused() && req.isReplayable() {
+               // If we try to reuse a connection that the server is in the process of
+               // closing, we may end up successfully writing out our request (or a
+               // portion of our request) only to find a connection error when we try to
+               // read from (or finish writing to) the socket.
+
+               // There can be a race between the socket pool checking whether a socket
+               // is still connected, receiving the FIN, and sending/reading data on a
+               // reused socket. If we receive the FIN between the connectedness check
+               // and writing/reading from the socket, we may first learn the socket is
+               // disconnected when we get a ERR_SOCKET_NOT_CONNECTED. This will most
+               // likely happen when trying to retrieve its IP address. See
+               // http://crbug.com/105824 for more details.
+
+               // We resend a request only if we reused a keep-alive connection and did
+               // not yet receive any header data. This automatically prevents an
+               // infinite resend loop because we'll run out of the cached keep-alive
+               // connections eventually.
+               return nil
+       }
+       return err
 }
 
+// ErrSkipAltProtocol is a sentinel error value defined by Transport.RegisterProtocol.
+var ErrSkipAltProtocol = errors.New("net/http: skip alternate protocol")
+
 // RegisterProtocol registers a new protocol with scheme.
 // The Transport will pass requests using the given scheme to rt.
 // It is rt's responsibility to simulate HTTP request semantics.
 //
 // RegisterProtocol can be used by other packages to provide
 // implementations of protocol schemes like "ftp" or "file".
+//
+// If rt.RoundTrip returns ErrSkipAltProtocol, the Transport will
+// handle the RoundTrip itself for that one request, as if the
+// protocol were not registered.
 func (t *Transport) RegisterProtocol(scheme string, rt RoundTripper) {
-       if scheme == "http" || scheme == "https" {
-               panic("protocol " + scheme + " already registered")
-       }
        t.altMu.Lock()
        defer t.altMu.Unlock()
        if t.altProto == nil {
@@ -261,6 +378,7 @@ func (t *Transport) RegisterProtocol(scheme string, rt RoundTripper) {
 // a "keep-alive" state. It does not interrupt any connections currently
 // in use.
 func (t *Transport) CloseIdleConnections() {
+       t.nextProtoOnce.Do(t.onceSetNextProtoDefaults)
        t.idleMu.Lock()
        m := t.idleConn
        t.idleConn = nil
@@ -269,13 +387,19 @@ func (t *Transport) CloseIdleConnections() {
        t.idleMu.Unlock()
        for _, conns := range m {
                for _, pconn := range conns {
-                       pconn.close()
+                       pconn.close(errCloseIdleConns)
                }
        }
+       if t2 := t.h2transport; t2 != nil {
+               t2.CloseIdleConnections()
+       }
 }
 
 // CancelRequest cancels an in-flight request by closing its connection.
 // CancelRequest should only be called after RoundTrip has returned.
+//
+// Deprecated: Use Request.Cancel instead. CancelRequest can not cancel
+// HTTP/2 requests.
 func (t *Transport) CancelRequest(req *Request) {
        t.reqMu.Lock()
        cancel := t.reqCanceler[req]
@@ -354,23 +478,41 @@ func (cm *connectMethod) proxyAuth() string {
        return ""
 }
 
-// putIdleConn adds pconn to the list of idle persistent connections awaiting
+// error values for debugging and testing, not seen by users.
+var (
+       errKeepAlivesDisabled = errors.New("http: putIdleConn: keep alives disabled")
+       errConnBroken         = errors.New("http: putIdleConn: connection is in bad state")
+       errWantIdle           = errors.New("http: putIdleConn: CloseIdleConnections was called")
+       errTooManyIdle        = errors.New("http: putIdleConn: too many idle connections")
+       errCloseIdleConns     = errors.New("http: CloseIdleConnections called")
+       errReadLoopExiting    = errors.New("http: persistConn.readLoop exiting")
+       errServerClosedIdle   = errors.New("http: server closed idle conn")
+)
+
+func (t *Transport) putOrCloseIdleConn(pconn *persistConn) {
+       if err := t.tryPutIdleConn(pconn); err != nil {
+               pconn.close(err)
+       }
+}
+
+// tryPutIdleConn adds pconn to the list of idle persistent connections awaiting
 // a new request.
-// If pconn is no longer needed or not in a good state, putIdleConn
-// returns false.
-func (t *Transport) putIdleConn(pconn *persistConn) bool {
+// If pconn is no longer needed or not in a good state, tryPutIdleConn returns
+// an error explaining why it wasn't registered.
+// tryPutIdleConn does not close pconn. Use putOrCloseIdleConn instead for that.
+func (t *Transport) tryPutIdleConn(pconn *persistConn) error {
        if t.DisableKeepAlives || t.MaxIdleConnsPerHost < 0 {
-               pconn.close()
-               return false
+               return errKeepAlivesDisabled
        }
        if pconn.isBroken() {
-               return false
+               return errConnBroken
        }
        key := pconn.cacheKey
        max := t.MaxIdleConnsPerHost
        if max == 0 {
                max = DefaultMaxIdleConnsPerHost
        }
+       pconn.markReused()
        t.idleMu.Lock()
 
        waitingDialer := t.idleConnCh[key]
@@ -382,7 +524,7 @@ func (t *Transport) putIdleConn(pconn *persistConn) bool {
                // first). Chrome calls this socket late binding.  See
                // https://insouciant.org/tech/connection-management-in-chromium/
                t.idleMu.Unlock()
-               return true
+               return nil
        default:
                if waitingDialer != nil {
                        // They had populated this, but their dial won
@@ -392,16 +534,14 @@ func (t *Transport) putIdleConn(pconn *persistConn) bool {
        }
        if t.wantIdle {
                t.idleMu.Unlock()
-               pconn.close()
-               return false
+               return errWantIdle
        }
        if t.idleConn == nil {
                t.idleConn = make(map[connectMethodKey][]*persistConn)
        }
        if len(t.idleConn[key]) >= max {
                t.idleMu.Unlock()
-               pconn.close()
-               return false
+               return errTooManyIdle
        }
        for _, exist := range t.idleConn[key] {
                if exist == pconn {
@@ -410,7 +550,7 @@ func (t *Transport) putIdleConn(pconn *persistConn) bool {
        }
        t.idleConn[key] = append(t.idleConn[key], pconn)
        t.idleMu.Unlock()
-       return true
+       return nil
 }
 
 // getIdleConnCh returns a channel to receive and return idle
@@ -494,16 +634,17 @@ func (t *Transport) replaceReqCanceler(r *Request, fn func()) bool {
        return true
 }
 
-func (t *Transport) dial(network, addr string) (c net.Conn, err error) {
+func (t *Transport) dial(network, addr string) (net.Conn, error) {
        if t.Dial != nil {
-               return t.Dial(network, addr)
+               c, err := t.Dial(network, addr)
+               if c == nil && err == nil {
+                       err = errors.New("net/http: Transport.Dial hook returned (nil, nil)")
+               }
+               return c, err
        }
        return net.Dial(network, addr)
 }
 
-// Testing hooks:
-var prePendingDial, postPendingDial func()
-
 // getConn dials and creates a new persistConn to the target as
 // specified in the connectMethod.  This includes doing a proxy CONNECT
 // and/or setting up TLS.  If this doesn't return an error, the persistConn
@@ -525,20 +666,16 @@ func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error
 
        // Copy these hooks so we don't race on the postPendingDial in
        // the goroutine we launch. Issue 11136.
-       prePendingDial := prePendingDial
-       postPendingDial := postPendingDial
+       testHookPrePendingDial := testHookPrePendingDial
+       testHookPostPendingDial := testHookPostPendingDial
 
        handlePendingDial := func() {
-               if prePendingDial != nil {
-                       prePendingDial()
-               }
+               testHookPrePendingDial()
                go func() {
                        if v := <-dialc; v.err == nil {
-                               t.putIdleConn(v.pc)
-                       }
-                       if postPendingDial != nil {
-                               postPendingDial()
+                               t.putOrCloseIdleConn(v.pc)
                        }
+                       testHookPostPendingDial()
                }()
        }
 
@@ -565,10 +702,10 @@ func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error
                return pc, nil
        case <-req.Cancel:
                handlePendingDial()
-               return nil, errors.New("net/http: request canceled while waiting for connection")
+               return nil, errRequestCanceledConn
        case <-cancelc:
                handlePendingDial()
-               return nil, errors.New("net/http: request canceled while waiting for connection")
+               return nil, errRequestCanceledConn
        }
 }
 
@@ -588,7 +725,16 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
                if err != nil {
                        return nil, err
                }
+               if pconn.conn == nil {
+                       return nil, errors.New("net/http: Transport.DialTLS returned (nil, nil)")
+               }
                if tc, ok := pconn.conn.(*tls.Conn); ok {
+                       // Handshake here, in case DialTLS didn't. TLSNextProto below
+                       // depends on it for knowing the connection state.
+                       if err := tc.Handshake(); err != nil {
+                               go pconn.conn.Close()
+                               return nil, err
+                       }
                        cs := tc.ConnectionState()
                        pconn.tlsState = &cs
                }
@@ -680,6 +826,12 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
                pconn.conn = tlsConn
        }
 
+       if s := pconn.tlsState; s != nil && s.NegotiatedProtocolIsMutual && s.NegotiatedProtocol != "" {
+               if next, ok := t.TLSNextProto[s.NegotiatedProtocol]; ok {
+                       return &persistConn{alt: next(cm.targetAddr, pconn.conn.(*tls.Conn))}, nil
+               }
+       }
+
        pconn.br = bufio.NewReader(noteEOFReader{pconn.conn, &pconn.sawEOF})
        pconn.bw = bufio.NewWriter(pconn.conn)
        go pconn.readLoop()
@@ -809,6 +961,11 @@ func (k connectMethodKey) String() string {
 // persistConn wraps a connection, usually a persistent one
 // (but may be used for non-keep-alive requests as well)
 type persistConn struct {
+       // alt optionally specifies the TLS NextProto RoundTripper.
+       // This is used for HTTP/2 today and future protocol laters.
+       // If it's non-nil, the rest of the fields are unused.
+       alt RoundTripper
+
        t        *Transport
        cacheKey connectMethodKey
        conn     net.Conn
@@ -828,9 +985,10 @@ type persistConn struct {
 
        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.
-       canceled             bool // whether this conn was broken due a CancelRequest
+       closed               error // set non-nil when conn is closed, before closech is closed
+       broken               bool  // an error has happened on this connection; marked broken so it's not reused.
+       canceled             bool  // whether this conn was broken due a CancelRequest
+       reused               bool  // whether conn has had successful request/response and is being reused.
        // mutateHeaderFunc is an optional func to modify extra
        // headers on each outbound request before it's written. (the
        // original Request given to RoundTrip is not modified)
@@ -852,15 +1010,34 @@ func (pc *persistConn) isCanceled() bool {
        return pc.canceled
 }
 
+// isReused reports whether this connection is in a known broken state.
+func (pc *persistConn) isReused() bool {
+       pc.lk.Lock()
+       r := pc.reused
+       pc.lk.Unlock()
+       return r
+}
+
 func (pc *persistConn) cancelRequest() {
        pc.lk.Lock()
        defer pc.lk.Unlock()
        pc.canceled = true
-       pc.closeLocked()
+       pc.closeLocked(errRequestCanceled)
 }
 
 func (pc *persistConn) readLoop() {
-       // eofc is used to block http.Handler goroutines reading from Response.Body
+       closeErr := errReadLoopExiting // default value, if not changed below
+       defer func() { pc.close(closeErr) }()
+
+       tryPutIdleConn := func() bool {
+               if err := pc.t.tryPutIdleConn(pc); err != nil {
+                       closeErr = err
+                       return false
+               }
+               return true
+       }
+
+       // eofc is used to block caller goroutines reading from Response.Body
        // at EOF until this goroutines has (potentially) added the connection
        // back to the idle pool.
        eofc := make(chan struct{})
@@ -873,17 +1050,14 @@ func (pc *persistConn) readLoop() {
 
        alive := true
        for alive {
-               pb, err := pc.br.Peek(1)
+               _, err := pc.br.Peek(1)
+               if err != nil {
+                       err = beforeRespHeaderError{err}
+               }
 
                pc.lk.Lock()
                if pc.numExpectedResponses == 0 {
-                       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.readLoopPeekFailLocked(err)
                        pc.lk.Unlock()
                        return
                }
@@ -893,115 +1067,189 @@ func (pc *persistConn) readLoop() {
 
                var resp *Response
                if err == nil {
-                       resp, err = ReadResponse(pc.br, rc.req)
-                       if err == nil && resp.StatusCode == 100 {
-                               // Skip any 100-continue for now.
-                               // TODO(bradfitz): if rc.req had "Expect: 100-continue",
-                               // actually block the request body write and signal the
-                               // writeLoop now to begin sending it. (Issue 2184) For now we
-                               // eat it, since we're never expecting one.
-                               resp, err = ReadResponse(pc.br, rc.req)
-                       }
-               }
-
-               if resp != nil {
-                       resp.TLS = pc.tlsState
+                       resp, err = pc.readResponse(rc)
                }
 
-               hasBody := resp != nil && rc.req.Method != "HEAD" && resp.ContentLength != 0
-
                if err != nil {
-                       pc.close()
-               } else {
-                       if rc.addedGzip && hasBody && resp.Header.Get("Content-Encoding") == "gzip" {
-                               resp.Header.Del("Content-Encoding")
-                               resp.Header.Del("Content-Length")
-                               resp.ContentLength = -1
-                               resp.Body = &gzipReader{body: resp.Body}
+                       // If we won't be able to retry this request later (from the
+                       // roundTrip goroutine), mark it as done now.
+                       // BEFORE the send on rc.ch, as the client might re-use the
+                       // same *Request pointer, and we don't want to set call
+                       // t.setReqCanceler from this persistConn while the Transport
+                       // potentially spins up a different persistConn for the
+                       // caller's subsequent request.
+                       if checkTransportResend(err, rc.req, pc) != nil {
+                               pc.t.setReqCanceler(rc.req, nil)
+                       }
+                       select {
+                       case rc.ch <- responseAndError{err: err}:
+                       case <-rc.callerGone:
+                               return
                        }
-                       resp.Body = &bodyEOFSignal{body: resp.Body}
+                       return
                }
 
-               if err != nil || resp.Close || rc.req.Close || resp.StatusCode <= 199 {
+               pc.lk.Lock()
+               pc.numExpectedResponses--
+               pc.lk.Unlock()
+
+               hasBody := rc.req.Method != "HEAD" && resp.ContentLength != 0
+
+               if resp.Close || rc.req.Close || resp.StatusCode <= 199 {
                        // Don't do keep-alive on error if either party requested a close
                        // or we get an unexpected informational (1xx) response.
                        // StatusCode 100 is already handled above.
                        alive = false
                }
 
-               var waitForBodyRead chan bool // channel is nil when there's no body
-               if hasBody {
-                       waitForBodyRead = make(chan bool, 2)
-                       resp.Body.(*bodyEOFSignal).earlyCloseFn = func() error {
-                               waitForBodyRead <- false
-                               return nil
-                       }
-                       resp.Body.(*bodyEOFSignal).fn = func(err error) error {
-                               isEOF := err == io.EOF
-                               waitForBodyRead <- isEOF
-                               if isEOF {
-                                       <-eofc // see comment at top
-                               } else if err != nil && pc.isCanceled() {
-                                       return errRequestCanceled
-                               }
-                               return err
-                       }
-               } else {
-                       // Before send on rc.ch, as client might re-use the
-                       // same *Request pointer, and we don't want to set this
-                       // on t from this persistConn while the Transport
-                       // potentially spins up a different persistConn for the
-                       // caller's subsequent request.
+               if !hasBody {
                        pc.t.setReqCanceler(rc.req, nil)
-               }
 
-               pc.lk.Lock()
-               pc.numExpectedResponses--
-               pc.lk.Unlock()
+                       // Put the idle conn back into the pool before we send the response
+                       // so if they process it quickly and make another request, they'll
+                       // get this same conn. But we use the unbuffered channel 'rc'
+                       // to guarantee that persistConn.roundTrip got out of its select
+                       // potentially waiting for this persistConn to close.
+                       // but after
+                       alive = alive &&
+                               !pc.sawEOF &&
+                               pc.wroteRequest() &&
+                               tryPutIdleConn()
 
-               // The connection might be going away when we put the
-               // idleConn below. When that happens, we close the response channel to signal
-               // to roundTrip that the connection is gone. roundTrip waits for
-               // both closing and a response in a select, so it might choose
-               // the close channel, rather than the response.
-               // We send the response first so that roundTrip can check
-               // if there is a pending one with a non-blocking select
-               // on the response channel before erroring out.
-               rc.ch <- responseAndError{resp, err}
-
-               if hasBody {
-                       // To avoid a race, wait for the just-returned
-                       // response body to be fully consumed before peek on
-                       // the underlying bufio reader.
                        select {
-                       case <-rc.req.Cancel:
-                               alive = false
-                               pc.t.CancelRequest(rc.req)
-                       case bodyEOF := <-waitForBodyRead:
-                               pc.t.setReqCanceler(rc.req, nil) // before pc might return to idle pool
-                               alive = alive &&
-                                       bodyEOF &&
-                                       !pc.sawEOF &&
-                                       pc.wroteRequest() &&
-                                       pc.t.putIdleConn(pc)
-                               if bodyEOF {
-                                       eofc <- struct{}{}
-                               }
-                       case <-pc.closech:
-                               alive = false
+                       case rc.ch <- responseAndError{res: resp}:
+                       case <-rc.callerGone:
+                               return
                        }
-               } else {
+
+                       // Now that they've read from the unbuffered channel, they're safely
+                       // out of the select that also waits on this goroutine to die, so
+                       // we're allowed to exit now if needed (if alive is false)
+                       testHookReadLoopBeforeNextRead()
+                       continue
+               }
+
+               if rc.addedGzip {
+                       maybeUngzipResponse(resp)
+               }
+               resp.Body = &bodyEOFSignal{body: resp.Body}
+
+               waitForBodyRead := make(chan bool, 2)
+               resp.Body.(*bodyEOFSignal).earlyCloseFn = func() error {
+                       waitForBodyRead <- false
+                       return nil
+               }
+               resp.Body.(*bodyEOFSignal).fn = func(err error) error {
+                       isEOF := err == io.EOF
+                       waitForBodyRead <- isEOF
+                       if isEOF {
+                               <-eofc // see comment above eofc declaration
+                       } else if err != nil && pc.isCanceled() {
+                               return errRequestCanceled
+                       }
+                       return err
+               }
+
+               select {
+               case rc.ch <- responseAndError{res: resp}:
+               case <-rc.callerGone:
+                       return
+               }
+
+               // Before looping back to the top of this function and peeking on
+               // the bufio.Reader, wait for the caller goroutine to finish
+               // reading the response body. (or for cancelation or death)
+               select {
+               case bodyEOF := <-waitForBodyRead:
+                       pc.t.setReqCanceler(rc.req, nil) // before pc might return to idle pool
                        alive = alive &&
+                               bodyEOF &&
                                !pc.sawEOF &&
                                pc.wroteRequest() &&
-                               pc.t.putIdleConn(pc)
+                               tryPutIdleConn()
+                       if bodyEOF {
+                               eofc <- struct{}{}
+                       }
+               case <-rc.req.Cancel:
+                       alive = false
+                       pc.t.CancelRequest(rc.req)
+               case <-pc.closech:
+                       alive = false
+               }
+
+               testHookReadLoopBeforeNextRead()
+       }
+}
+
+func maybeUngzipResponse(resp *Response) {
+       if resp.Header.Get("Content-Encoding") == "gzip" {
+               resp.Header.Del("Content-Encoding")
+               resp.Header.Del("Content-Length")
+               resp.ContentLength = -1
+               resp.Body = &gzipReader{body: resp.Body}
+       }
+}
+
+func (pc *persistConn) readLoopPeekFailLocked(peekErr error) {
+       if pc.closed != nil {
+               return
+       }
+       if n := pc.br.Buffered(); n > 0 {
+               buf, _ := pc.br.Peek(n)
+               log.Printf("Unsolicited response received on idle HTTP channel starting with %q; err=%v", buf, peekErr)
+       }
+       if peekErr == io.EOF {
+               // common case.
+               pc.closeLocked(errServerClosedIdle)
+       } else {
+               pc.closeLocked(fmt.Errorf("readLoopPeekFailLocked: %v", peekErr))
+       }
+}
+
+// readResponse reads an HTTP response (or two, in the case of "Expect:
+// 100-continue") from the server. It returns the final non-100 one.
+func (pc *persistConn) readResponse(rc requestAndChan) (resp *Response, err error) {
+       resp, err = ReadResponse(pc.br, rc.req)
+       if err != nil {
+               return
+       }
+       if rc.continueCh != nil {
+               if resp.StatusCode == 100 {
+                       rc.continueCh <- struct{}{}
+               } else {
+                       close(rc.continueCh)
+               }
+       }
+       if resp.StatusCode == 100 {
+               resp, err = ReadResponse(pc.br, rc.req)
+               if err != nil {
+                       return
                }
+       }
+       resp.TLS = pc.tlsState
+       return
+}
+
+// waitForContinue returns the function to block until
+// any response, timeout or connection close. After any of them,
+// the function returns a bool which indicates if the body should be sent.
+func (pc *persistConn) waitForContinue(continueCh <-chan struct{}) func() bool {
+       if continueCh == nil {
+               return nil
+       }
+       return func() bool {
+               timer := time.NewTimer(pc.t.ExpectContinueTimeout)
+               defer timer.Stop()
 
-               if hook := testHookReadLoopBeforeNextRead; hook != nil {
-                       hook()
+               select {
+               case _, ok := <-continueCh:
+                       return ok
+               case <-timer.C:
+                       return true
+               case <-pc.closech:
+                       return false
                }
        }
-       pc.close()
 }
 
 func (pc *persistConn) writeLoop() {
@@ -1012,7 +1260,7 @@ func (pc *persistConn) writeLoop() {
                                wr.ch <- errors.New("http: can't write HTTP request on broken connection")
                                continue
                        }
-                       err := wr.req.Request.write(pc.bw, pc.isProxy, wr.req.extra)
+                       err := wr.req.Request.write(pc.bw, pc.isProxy, wr.req.extra, pc.waitForContinue(wr.continueCh))
                        if err == nil {
                                err = pc.bw.Flush()
                        }
@@ -1056,19 +1304,29 @@ func (pc *persistConn) wroteRequest() bool {
        }
 }
 
+// responseAndError is how the goroutine reading from an HTTP/1 server
+// communicates with the goroutine doing the RoundTrip.
 type responseAndError struct {
-       res *Response
+       res *Response // else use this response (see res method)
        err error
 }
 
 type requestAndChan struct {
        req *Request
-       ch  chan responseAndError
+       ch  chan responseAndError // unbuffered; always send in select on callerGone
 
        // did the Transport (as opposed to the client code) add an
        // Accept-Encoding gzip header? only if it we set it do
        // we transparently decode the gzip.
        addedGzip bool
+
+       // Optional blocking chan for Expect: 100-continue (for send).
+       // If the request has an "Expect: 100-continue" header and
+       // the server responds 100 Continue, readLoop send a value
+       // to writeLoop via this chan.
+       continueCh chan<- struct{}
+
+       callerGone <-chan struct{} // closed when roundTrip caller has returned
 }
 
 // A writeRequest is sent by the readLoop's goroutine to the
@@ -1078,6 +1336,11 @@ type requestAndChan struct {
 type writeRequest struct {
        req *transportRequest
        ch  chan<- error
+
+       // Optional blocking chan for Expect: 100-continue (for recieve).
+       // If not nil, writeLoop blocks sending request body until
+       // it receives from this chan.
+       continueCh <-chan struct{}
 }
 
 type httpError struct {
@@ -1090,23 +1353,34 @@ func (e *httpError) Timeout() bool   { return e.timeout }
 func (e *httpError) Temporary() bool { return true }
 
 var errTimeout error = &httpError{err: "net/http: timeout awaiting response headers", timeout: true}
-var errClosed error = &httpError{err: "net/http: transport closed before response was received"}
+var errClosed error = &httpError{err: "net/http: server closed connection before response was received"}
 var errRequestCanceled = errors.New("net/http: request canceled")
+var errRequestCanceledConn = errors.New("net/http: request canceled while waiting for connection") // TODO: unify?
+
+func nop() {}
 
-// nil except for tests
+// testHooks. Always non-nil.
 var (
-       testHookPersistConnClosedGotRes func()
-       testHookEnterRoundTrip          func()
-       testHookMu                      sync.Locker = fakeLocker{} // guards following
-       testHookReadLoopBeforeNextRead  func()
+       testHookEnterRoundTrip   = nop
+       testHookWaitResLoop      = nop
+       testHookRoundTripRetried = nop
+       testHookPrePendingDial   = nop
+       testHookPostPendingDial  = nop
+
+       testHookMu                     sync.Locker = fakeLocker{} // guards following
+       testHookReadLoopBeforeNextRead             = nop
 )
 
+// beforeRespHeaderError is used to indicate when an IO error has occurred before
+// any header data was received.
+type beforeRespHeaderError struct {
+       error
+}
+
 func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err error) {
-       if hook := testHookEnterRoundTrip; hook != nil {
-               hook()
-       }
+       testHookEnterRoundTrip()
        if !pc.t.replaceReqCanceler(req.Request, pc.cancelRequest) {
-               pc.t.putIdleConn(pc)
+               pc.t.putOrCloseIdleConn(pc)
                return nil, errRequestCanceled
        }
        pc.lk.Lock()
@@ -1143,42 +1417,47 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
                req.extraHeaders().Set("Accept-Encoding", "gzip")
        }
 
+       var continueCh chan struct{}
+       if req.ProtoAtLeast(1, 1) && req.Body != nil && req.expectsContinue() {
+               continueCh = make(chan struct{}, 1)
+       }
+
        if pc.t.DisableKeepAlives {
                req.extraHeaders().Set("Connection", "close")
        }
 
+       gone := make(chan struct{})
+       defer close(gone)
+
        // Write the request concurrently with waiting for a response,
        // in case the server decides to reply before reading our full
        // request body.
        writeErrCh := make(chan error, 1)
-       pc.writech <- writeRequest{req, writeErrCh}
+       pc.writech <- writeRequest{req, writeErrCh, continueCh}
 
-       resc := make(chan responseAndError, 1)
-       pc.reqch <- requestAndChan{req.Request, resc, requestedGzip}
+       resc := make(chan responseAndError)
+       pc.reqch <- requestAndChan{
+               req:        req.Request,
+               ch:         resc,
+               addedGzip:  requestedGzip,
+               continueCh: continueCh,
+               callerGone: gone,
+       }
 
        var re responseAndError
        var respHeaderTimer <-chan time.Time
        cancelChan := req.Request.Cancel
 WaitResponse:
        for {
+               testHookWaitResLoop()
                select {
                case err := <-writeErrCh:
-                       if isNetWriteError(err) {
-                               // Issue 11745. If we failed to write the request
-                               // body, it's possible the server just heard enough
-                               // and already wrote to us. Prioritize the server's
-                               // response over returning a body write error.
-                               select {
-                               case re = <-resc:
-                                       pc.close()
-                                       break WaitResponse
-                               case <-time.After(50 * time.Millisecond):
-                                       // Fall through.
-                               }
-                       }
                        if err != nil {
-                               re = responseAndError{nil, err}
-                               pc.close()
+                               if pc.isCanceled() {
+                                       err = errRequestCanceled
+                               }
+                               re = responseAndError{err: beforeRespHeaderError{err}}
+                               pc.close(fmt.Errorf("write error: %v", err))
                                break WaitResponse
                        }
                        if d := pc.t.ResponseHeaderTimeout; d > 0 {
@@ -1187,33 +1466,22 @@ WaitResponse:
                                respHeaderTimer = timer.C
                        }
                case <-pc.closech:
-                       // The persist connection is dead. This shouldn't
-                       // usually happen (only with Connection: close responses
-                       // with no response bodies), but if it does happen it
-                       // means either a) the remote server hung up on us
-                       // prematurely, or b) the readLoop sent us a response &
-                       // closed its closech at roughly the same time, and we
-                       // selected this case first. If we got a response, readLoop makes sure
-                       // to send it before it puts the conn and closes the channel.
-                       // That way, we can fetch the response, if there is one,
-                       // with a non-blocking receive.
-                       select {
-                       case re = <-resc:
-                               if fn := testHookPersistConnClosedGotRes; fn != nil {
-                                       fn()
-                               }
-                       default:
-                               re = responseAndError{err: errClosed}
-                               if pc.isCanceled() {
-                                       re = responseAndError{err: errRequestCanceled}
-                               }
+                       var err error
+                       if pc.isCanceled() {
+                               err = errRequestCanceled
+                       } else {
+                               err = beforeRespHeaderError{fmt.Errorf("net/http: HTTP/1 transport connection broken: %v", pc.closed)}
                        }
+                       re = responseAndError{err: err}
                        break WaitResponse
                case <-respHeaderTimer:
-                       pc.close()
+                       pc.close(errTimeout)
                        re = responseAndError{err: errTimeout}
                        break WaitResponse
                case re = <-resc:
+                       if re.err != nil && pc.isCanceled() {
+                               re.err = errRequestCanceled
+                       }
                        break WaitResponse
                case <-cancelChan:
                        pc.t.CancelRequest(req.Request)
@@ -1224,6 +1492,9 @@ WaitResponse:
        if re.err != nil {
                pc.t.setReqCanceler(req.Request, nil)
        }
+       if (re.res == nil) == (re.err == nil) {
+               panic("internal error: exactly one of res or err should be set")
+       }
        return re.res, re.err
 }
 
@@ -1236,18 +1507,44 @@ func (pc *persistConn) markBroken() {
        pc.broken = true
 }
 
-func (pc *persistConn) close() {
+// markReused marks this connection as having been successfully used for a
+// request and response.
+func (pc *persistConn) markReused() {
+       pc.lk.Lock()
+       pc.reused = true
+       pc.lk.Unlock()
+}
+
+// close closes the underlying TCP connection and closes
+// the pc.closech channel.
+//
+// The provided err is only for testing and debugging; in normal
+// circumstances it should never be seen by users.
+func (pc *persistConn) close(err error) {
        pc.lk.Lock()
        defer pc.lk.Unlock()
-       pc.closeLocked()
+       pc.closeLocked(err)
 }
 
-func (pc *persistConn) closeLocked() {
+func (pc *persistConn) closeLocked(err error) {
+       if err == nil {
+               panic("nil error")
+       }
        pc.broken = true
-       if !pc.closed {
-               pc.conn.Close()
-               pc.closed = true
-               close(pc.closech)
+       if pc.closed == nil {
+               pc.closed = err
+               if pc.alt != nil {
+                       // Do nothing; can only get here via getConn's
+                       // handlePendingDial's putOrCloseIdleConn when
+                       // it turns out the abandoned connection in
+                       // flight ended up negotiating an alternate
+                       // protocol.  We don't use the connection
+                       // freelist for http2. That's done by the
+                       // alternate protocol's RoundTripper.
+               } else {
+                       pc.conn.Close()
+                       close(pc.closech)
+               }
        }
        pc.mutateHeaderFunc = nil
 }
index c21d4afa87f1ecfe6997d9fef38dc6d380f516aa..3b2a5f978e263557feca946c0f1af4eed838cf86 100644 (file)
@@ -2,7 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Tests for transport.go
+// Tests for transport.go.
+//
+// More tests are in clientserver_test.go (for things testing both client & server for both
+// HTTP/1 and HTTP/2). This
 
 package http_test
 
@@ -20,6 +23,8 @@ import (
        "net"
        . "net/http"
        "net/http/httptest"
+       "net/http/httputil"
+       "net/http/internal"
        "net/url"
        "os"
        "reflect"
@@ -256,6 +261,7 @@ func TestTransportConnectionCloseOnRequest(t *testing.T) {
 
 // if the Transport's DisableKeepAlives is set, all requests should
 // send Connection: close.
+// HTTP/1-only (Connection: close doesn't exist in h2)
 func TestTransportConnectionCloseOnRequestDisableKeepAlive(t *testing.T) {
        defer afterTest(t)
        ts := httptest.NewServer(hostPortHandler)
@@ -431,6 +437,7 @@ func TestTransportMaxPerHostIdleConns(t *testing.T) {
 }
 
 func TestTransportServerClosingUnexpectedly(t *testing.T) {
+       setParallel(t)
        defer afterTest(t)
        ts := httptest.NewServer(hostPortHandler)
        defer ts.Close()
@@ -597,6 +604,7 @@ func TestTransportHeadChunkedResponse(t *testing.T) {
 
        tr := &Transport{DisableKeepAlives: false}
        c := &Client{Transport: tr}
+       defer tr.CloseIdleConnections()
 
        // Ensure that we wait for the readLoop to complete before
        // calling Head again
@@ -790,6 +798,94 @@ func TestTransportGzip(t *testing.T) {
        }
 }
 
+// If a request has Expect:100-continue header, the request blocks sending body until the first response.
+// Premature consumption of the request body should not be occurred.
+func TestTransportExpect100Continue(t *testing.T) {
+       defer afterTest(t)
+
+       ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+               switch req.URL.Path {
+               case "/100":
+                       // This endpoint implicitly responds 100 Continue and reads body.
+                       if _, err := io.Copy(ioutil.Discard, req.Body); err != nil {
+                               t.Error("Failed to read Body", err)
+                       }
+                       rw.WriteHeader(StatusOK)
+               case "/200":
+                       // Go 1.5 adds Connection: close header if the client expect
+                       // continue but not entire request body is consumed.
+                       rw.WriteHeader(StatusOK)
+               case "/500":
+                       rw.WriteHeader(StatusInternalServerError)
+               case "/keepalive":
+                       // This hijacked endpoint responds error without Connection:close.
+                       _, bufrw, err := rw.(Hijacker).Hijack()
+                       if err != nil {
+                               log.Fatal(err)
+                       }
+                       bufrw.WriteString("HTTP/1.1 500 Internal Server Error\r\n")
+                       bufrw.WriteString("Content-Length: 0\r\n\r\n")
+                       bufrw.Flush()
+               case "/timeout":
+                       // This endpoint tries to read body without 100 (Continue) response.
+                       // After ExpectContinueTimeout, the reading will be started.
+                       conn, bufrw, err := rw.(Hijacker).Hijack()
+                       if err != nil {
+                               log.Fatal(err)
+                       }
+                       if _, err := io.CopyN(ioutil.Discard, bufrw, req.ContentLength); err != nil {
+                               t.Error("Failed to read Body", err)
+                       }
+                       bufrw.WriteString("HTTP/1.1 200 OK\r\n\r\n")
+                       bufrw.Flush()
+                       conn.Close()
+               }
+
+       }))
+       defer ts.Close()
+
+       tests := []struct {
+               path   string
+               body   []byte
+               sent   int
+               status int
+       }{
+               {path: "/100", body: []byte("hello"), sent: 5, status: 200},       // Got 100 followed by 200, entire body is sent.
+               {path: "/200", body: []byte("hello"), sent: 0, status: 200},       // Got 200 without 100. body isn't sent.
+               {path: "/500", body: []byte("hello"), sent: 0, status: 500},       // Got 500 without 100. body isn't sent.
+               {path: "/keepalive", body: []byte("hello"), sent: 0, status: 500}, // Althogh without Connection:close, body isn't sent.
+               {path: "/timeout", body: []byte("hello"), sent: 5, status: 200},   // Timeout exceeded and entire body is sent.
+       }
+
+       for i, v := range tests {
+               tr := &Transport{ExpectContinueTimeout: 2 * time.Second}
+               defer tr.CloseIdleConnections()
+               c := &Client{Transport: tr}
+
+               body := bytes.NewReader(v.body)
+               req, err := NewRequest("PUT", ts.URL+v.path, body)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               req.Header.Set("Expect", "100-continue")
+               req.ContentLength = int64(len(v.body))
+
+               resp, err := c.Do(req)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               resp.Body.Close()
+
+               sent := len(v.body) - body.Len()
+               if v.status != resp.StatusCode {
+                       t.Errorf("test %d: status code should be %d but got %d. (%s)", i, v.status, resp.StatusCode, v.path)
+               }
+               if v.sent != sent {
+                       t.Errorf("test %d: sent body should be %d but sent %d. (%s)", i, v.sent, sent, v.path)
+               }
+       }
+}
+
 func TestTransportProxy(t *testing.T) {
        defer afterTest(t)
        ch := make(chan string, 1)
@@ -874,9 +970,7 @@ func TestTransportGzipShort(t *testing.T) {
 
 // tests that persistent goroutine connections shut down when no longer desired.
 func TestTransportPersistConnLeak(t *testing.T) {
-       if runtime.GOOS == "plan9" {
-               t.Skip("skipping test; see https://golang.org/issue/7237")
-       }
+       setParallel(t)
        defer afterTest(t)
        gotReqCh := make(chan bool)
        unblockCh := make(chan bool)
@@ -943,9 +1037,7 @@ func TestTransportPersistConnLeak(t *testing.T) {
 // golang.org/issue/4531: Transport leaks goroutines when
 // request.ContentLength is explicitly short
 func TestTransportPersistConnLeakShortBody(t *testing.T) {
-       if runtime.GOOS == "plan9" {
-               t.Skip("skipping test; see https://golang.org/issue/7237")
-       }
+       setParallel(t)
        defer afterTest(t)
        ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
        }))
@@ -1286,6 +1378,7 @@ func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) {
 }
 
 func TestTransportResponseHeaderTimeout(t *testing.T) {
+       setParallel(t)
        defer afterTest(t)
        if testing.Short() {
                t.Skip("skipping timeout test in -short mode")
@@ -1357,6 +1450,7 @@ func TestTransportResponseHeaderTimeout(t *testing.T) {
 }
 
 func TestTransportCancelRequest(t *testing.T) {
+       setParallel(t)
        defer afterTest(t)
        if testing.Short() {
                t.Skip("skipping test in -short mode")
@@ -1466,6 +1560,7 @@ Get = Get http://something.no-network.tld/: net/http: request canceled while wai
 }
 
 func TestCancelRequestWithChannel(t *testing.T) {
+       setParallel(t)
        defer afterTest(t)
        if testing.Short() {
                t.Skip("skipping test in -short mode")
@@ -1523,6 +1618,7 @@ func TestCancelRequestWithChannel(t *testing.T) {
 }
 
 func TestCancelRequestWithChannelBeforeDo(t *testing.T) {
+       setParallel(t)
        defer afterTest(t)
        unblockc := make(chan bool)
        ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -1554,7 +1650,6 @@ func TestCancelRequestWithChannelBeforeDo(t *testing.T) {
 
 // Issue 11020. The returned error message should be errRequestCanceled
 func TestTransportCancelBeforeResponseHeaders(t *testing.T) {
-       t.Skip("Skipping flaky test; see Issue 11894")
        defer afterTest(t)
 
        serverConnCh := make(chan net.Conn, 1)
@@ -1704,6 +1799,19 @@ func TestTransportNoHost(t *testing.T) {
        }
 }
 
+// Issue 13311
+func TestTransportEmptyMethod(t *testing.T) {
+       req, _ := NewRequest("GET", "http://foo.com/", nil)
+       req.Method = ""                                 // docs say "For client requests an empty string means GET"
+       got, err := httputil.DumpRequestOut(req, false) // DumpRequestOut uses Transport
+       if err != nil {
+               t.Fatal(err)
+       }
+       if !strings.Contains(string(got), "GET ") {
+               t.Fatalf("expected substring 'GET '; got: %s", got)
+       }
+}
+
 func TestTransportSocketLateBinding(t *testing.T) {
        defer afterTest(t)
 
@@ -2291,15 +2399,103 @@ type errorReader struct {
 
 func (e errorReader) Read(p []byte) (int, error) { return 0, e.err }
 
+type plan9SleepReader struct{}
+
+func (plan9SleepReader) Read(p []byte) (int, error) {
+       if runtime.GOOS == "plan9" {
+               // After the fix to unblock TCP Reads in
+               // https://golang.org/cl/15941, this sleep is required
+               // on plan9 to make sure TCP Writes before an
+               // immediate TCP close go out on the wire.  On Plan 9,
+               // it seems that a hangup of a TCP connection with
+               // queued data doesn't send the queued data first.
+               // https://golang.org/issue/9554
+               time.Sleep(50 * time.Millisecond)
+       }
+       return 0, io.EOF
+}
+
 type closerFunc func() error
 
 func (f closerFunc) Close() error { return f() }
 
+// Issue 4677. If we try to reuse a connection that the server is in the
+// process of closing, we may end up successfully writing out our request (or a
+// portion of our request) only to find a connection error when we try to read
+// from (or finish writing to) the socket.
+//
+// NOTE: we resend a request only if the request is idempotent, we reused a
+// keep-alive connection, and we haven't yet received any header data.  This
+// automatically prevents an infinite resend loop because we'll run out of the
+// cached keep-alive connections eventually.
+func TestRetryIdempotentRequestsOnError(t *testing.T) {
+       defer afterTest(t)
+
+       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+       }))
+       defer ts.Close()
+
+       tr := &Transport{}
+       c := &Client{Transport: tr}
+
+       const N = 2
+       retryc := make(chan struct{}, N)
+       SetRoundTripRetried(func() {
+               retryc <- struct{}{}
+       })
+       defer SetRoundTripRetried(nil)
+
+       for n := 0; n < 100; n++ {
+               // open 2 conns
+               errc := make(chan error, N)
+               for i := 0; i < N; i++ {
+                       // start goroutines, send on errc
+                       go func() {
+                               res, err := c.Get(ts.URL)
+                               if err == nil {
+                                       res.Body.Close()
+                               }
+                               errc <- err
+                       }()
+               }
+               for i := 0; i < N; i++ {
+                       if err := <-errc; err != nil {
+                               t.Fatal(err)
+                       }
+               }
+
+               ts.CloseClientConnections()
+               for i := 0; i < N; i++ {
+                       go func() {
+                               res, err := c.Get(ts.URL)
+                               if err == nil {
+                                       res.Body.Close()
+                               }
+                               errc <- err
+                       }()
+               }
+
+               for i := 0; i < N; i++ {
+                       if err := <-errc; err != nil {
+                               t.Fatal(err)
+                       }
+               }
+               for i := 0; i < N; i++ {
+                       select {
+                       case <-retryc:
+                               // we triggered a retry, test was successful
+                               t.Logf("finished after %d runs\n", n)
+                               return
+                       default:
+                       }
+               }
+       }
+       t.Fatal("did not trigger any retries")
+}
+
 // Issue 6981
 func TestTransportClosesBodyOnError(t *testing.T) {
-       if runtime.GOOS == "plan9" {
-               t.Skip("skipping test; see https://golang.org/issue/7782")
-       }
+       setParallel(t)
        defer afterTest(t)
        readBody := make(chan error, 1)
        ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -2313,7 +2509,7 @@ func TestTransportClosesBodyOnError(t *testing.T) {
                io.Reader
                io.Closer
        }{
-               io.MultiReader(io.LimitReader(neverEnding('x'), 1<<20), errorReader{fakeErr}),
+               io.MultiReader(io.LimitReader(neverEnding('x'), 1<<20), plan9SleepReader{}, errorReader{fakeErr}),
                closerFunc(func() error {
                        select {
                        case didClose <- true:
@@ -2474,52 +2670,6 @@ func TestTransportRangeAndGzip(t *testing.T) {
        res.Body.Close()
 }
 
-// Previously, we used to handle a logical race within RoundTrip by waiting for 100ms
-// in the case of an error. Changing the order of the channel operations got rid of this
-// race.
-//
-// In order to test that the channel op reordering works, we install a hook into the
-// roundTrip function which gets called if we saw the connection go away and
-// we subsequently received a response.
-func TestTransportResponseCloseRace(t *testing.T) {
-       if testing.Short() {
-               t.Skip("skipping in short mode")
-       }
-       defer afterTest(t)
-
-       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-       }))
-       defer ts.Close()
-       sawRace := false
-       SetInstallConnClosedHook(func() {
-               sawRace = true
-       })
-       defer SetInstallConnClosedHook(nil)
-       tr := &Transport{
-               DisableKeepAlives: true,
-       }
-       req, err := NewRequest("GET", ts.URL, nil)
-       if err != nil {
-               t.Fatal(err)
-       }
-       // selects are not deterministic, so do this a bunch
-       // and see if we handle the logical race at least once.
-       for i := 0; i < 10000; i++ {
-               resp, err := tr.RoundTrip(req)
-               if err != nil {
-                       t.Fatalf("unexpected error: %s", err)
-                       continue
-               }
-               resp.Body.Close()
-               if sawRace {
-                       break
-               }
-       }
-       if !sawRace {
-               t.Errorf("didn't see response/connection going away race")
-       }
-}
-
 // Test for issue 10474
 func TestTransportResponseCancelRace(t *testing.T) {
        defer afterTest(t)
@@ -2645,7 +2795,7 @@ func TestTransportFlushesBodyChunks(t *testing.T) {
                req.Header.Set("User-Agent", "x") // known value for test
                res, err := tr.RoundTrip(req)
                if err != nil {
-                       t.Error("RoundTrip: %v", err)
+                       t.Errorf("RoundTrip: %v", err)
                        close(resc)
                        return
                }
@@ -2735,6 +2885,153 @@ func TestTransportPrefersResponseOverWriteError(t *testing.T) {
        }
 }
 
+func TestTransportAutomaticHTTP2(t *testing.T) {
+       tr := &Transport{}
+       _, err := tr.RoundTrip(new(Request))
+       if err == nil {
+               t.Error("expected error from RoundTrip")
+       }
+       if tr.TLSNextProto["h2"] == nil {
+               t.Errorf("HTTP/2 not registered.")
+       }
+
+       // Now with TLSNextProto set:
+       tr = &Transport{TLSNextProto: make(map[string]func(string, *tls.Conn) RoundTripper)}
+       _, err = tr.RoundTrip(new(Request))
+       if err == nil {
+               t.Error("expected error from RoundTrip")
+       }
+       if tr.TLSNextProto["h2"] != nil {
+               t.Errorf("HTTP/2 registered, despite non-nil TLSNextProto field")
+       }
+}
+
+// Issue 13633: there was a race where we returned bodyless responses
+// to callers before recycling the persistent connection, which meant
+// a client doing two subsequent requests could end up on different
+// connections. It's somewhat harmless but enough tests assume it's
+// not true in order to test other things that it's worth fixing.
+// Plus it's nice to be consistent and not have timing-dependent
+// behavior.
+func TestTransportReuseConnEmptyResponseBody(t *testing.T) {
+       defer afterTest(t)
+       cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
+               w.Header().Set("X-Addr", r.RemoteAddr)
+               // Empty response body.
+       }))
+       defer cst.close()
+       n := 100
+       if testing.Short() {
+               n = 10
+       }
+       var firstAddr string
+       for i := 0; i < n; i++ {
+               res, err := cst.c.Get(cst.ts.URL)
+               if err != nil {
+                       log.Fatal(err)
+               }
+               addr := res.Header.Get("X-Addr")
+               if i == 0 {
+                       firstAddr = addr
+               } else if addr != firstAddr {
+                       t.Fatalf("On request %d, addr %q != original addr %q", i+1, addr, firstAddr)
+               }
+               res.Body.Close()
+       }
+}
+
+// Issue 13839
+func TestNoCrashReturningTransportAltConn(t *testing.T) {
+       cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey)
+       if err != nil {
+               t.Fatal(err)
+       }
+       ln := newLocalListener(t)
+       defer ln.Close()
+
+       handledPendingDial := make(chan bool, 1)
+       SetPendingDialHooks(nil, func() { handledPendingDial <- true })
+       defer SetPendingDialHooks(nil, nil)
+
+       testDone := make(chan struct{})
+       defer close(testDone)
+       go func() {
+               tln := tls.NewListener(ln, &tls.Config{
+                       NextProtos:   []string{"foo"},
+                       Certificates: []tls.Certificate{cert},
+               })
+               sc, err := tln.Accept()
+               if err != nil {
+                       t.Error(err)
+                       return
+               }
+               if err := sc.(*tls.Conn).Handshake(); err != nil {
+                       t.Error(err)
+                       return
+               }
+               <-testDone
+               sc.Close()
+       }()
+
+       addr := ln.Addr().String()
+
+       req, _ := NewRequest("GET", "https://fake.tld/", nil)
+       cancel := make(chan struct{})
+       req.Cancel = cancel
+
+       doReturned := make(chan bool, 1)
+       madeRoundTripper := make(chan bool, 1)
+
+       tr := &Transport{
+               DisableKeepAlives: true,
+               TLSNextProto: map[string]func(string, *tls.Conn) RoundTripper{
+                       "foo": func(authority string, c *tls.Conn) RoundTripper {
+                               madeRoundTripper <- true
+                               return funcRoundTripper(func() {
+                                       t.Error("foo RoundTripper should not be called")
+                               })
+                       },
+               },
+               Dial: func(_, _ string) (net.Conn, error) {
+                       panic("shouldn't be called")
+               },
+               DialTLS: func(_, _ string) (net.Conn, error) {
+                       tc, err := tls.Dial("tcp", addr, &tls.Config{
+                               InsecureSkipVerify: true,
+                               NextProtos:         []string{"foo"},
+                       })
+                       if err != nil {
+                               return nil, err
+                       }
+                       if err := tc.Handshake(); err != nil {
+                               return nil, err
+                       }
+                       close(cancel)
+                       <-doReturned
+                       return tc, nil
+               },
+       }
+       c := &Client{Transport: tr}
+
+       _, err = c.Do(req)
+       if ue, ok := err.(*url.Error); !ok || ue.Err != ExportErrRequestCanceledConn {
+               t.Fatalf("Do error = %v; want url.Error with errRequestCanceledConn", err)
+       }
+
+       doReturned <- true
+       <-madeRoundTripper
+       <-handledPendingDial
+}
+
+var errFakeRoundTrip = errors.New("fake roundtrip")
+
+type funcRoundTripper func()
+
+func (fn funcRoundTripper) RoundTrip(*Request) (*Response, error) {
+       fn()
+       return nil, errFakeRoundTrip
+}
+
 func wantBody(res *Response, err error, want string) error {
        if err != nil {
                return err
index 232d6508906328a53855a995cd63db02bcc3f477..cfbc5778c1cc499097a3362e4dca3b350dd664cb 100644 (file)
@@ -134,8 +134,5 @@ func main() {
        http.HandleFunc("/args", ArgServer)
        http.HandleFunc("/go/hello", HelloServer)
        http.HandleFunc("/date", DateServer)
-       err := http.ListenAndServe(":12345", nil)
-       if err != nil {
-               log.Panicln("ListenAndServe:", err)
-       }
+       log.Fatal(http.ListenAndServe(":12345", nil))
 }
index 567d18de448cb8a959b80c989fd2dc7db52ffecd..7bdd924150371e9c6d369929dbb9389c9ce840ad 100644 (file)
@@ -185,21 +185,50 @@ func testAddrs(t *testing.T, ifat []Addr) (naf4, naf6 int) {
                                t.Errorf("unexpected value: %#v", ifa)
                                continue
                        }
+                       if len(ifa.IP) != IPv6len {
+                               t.Errorf("should be internal representation either IPv6 or IPv6 IPv4-mapped address: %#v", ifa)
+                               continue
+                       }
                        prefixLen, maxPrefixLen := ifa.Mask.Size()
                        if ifa.IP.To4() != nil {
                                if 0 >= prefixLen || prefixLen > 8*IPv4len || maxPrefixLen != 8*IPv4len {
-                                       t.Errorf("unexpected prefix length: %v/%v", prefixLen, maxPrefixLen)
+                                       t.Errorf("unexpected prefix length: %d/%d", prefixLen, maxPrefixLen)
+                                       continue
+                               }
+                               if ifa.IP.IsLoopback() && (prefixLen != 8 && prefixLen != 8*IPv4len) { // see RFC 1122
+                                       t.Errorf("unexpected prefix length for IPv4 loopback: %d/%d", prefixLen, maxPrefixLen)
                                        continue
                                }
                                naf4++
-                       } else if ifa.IP.To16() != nil {
+                       }
+                       if ifa.IP.To16() != nil && ifa.IP.To4() == nil {
                                if 0 >= prefixLen || prefixLen > 8*IPv6len || maxPrefixLen != 8*IPv6len {
-                                       t.Errorf("unexpected prefix length: %v/%v", prefixLen, maxPrefixLen)
+                                       t.Errorf("unexpected prefix length: %d/%d", prefixLen, maxPrefixLen)
+                                       continue
+                               }
+                               if ifa.IP.IsLoopback() && prefixLen != 8*IPv6len { // see RFC 4291
+                                       t.Errorf("unexpected prefix length for IPv6 loopback: %d/%d", prefixLen, maxPrefixLen)
                                        continue
                                }
                                naf6++
                        }
                        t.Logf("interface address %q", ifa.String())
+               case *IPAddr:
+                       if ifa == nil || ifa.IP == nil || ifa.IP.IsUnspecified() || ifa.IP.IsMulticast() {
+                               t.Errorf("unexpected value: %#v", ifa)
+                               continue
+                       }
+                       if len(ifa.IP) != IPv6len {
+                               t.Errorf("should be internal representation either IPv6 or IPv6 IPv4-mapped address: %#v", ifa)
+                               continue
+                       }
+                       if ifa.IP.To4() != nil {
+                               naf4++
+                       }
+                       if ifa.IP.To16() != nil && ifa.IP.To4() == nil {
+                               naf6++
+                       }
+                       t.Logf("interface address %s", ifa.String())
                default:
                        t.Errorf("unexpected type: %T", ifa)
                }
@@ -212,12 +241,17 @@ func testMulticastAddrs(t *testing.T, ifmat []Addr) (nmaf4, nmaf6 int) {
                switch ifma := ifma.(type) {
                case *IPAddr:
                        if ifma == nil || ifma.IP == nil || ifma.IP.IsUnspecified() || !ifma.IP.IsMulticast() {
-                               t.Errorf("unexpected value: %#v", ifma)
+                               t.Errorf("unexpected value: %+v", ifma)
+                               continue
+                       }
+                       if len(ifma.IP) != IPv6len {
+                               t.Errorf("should be internal representation either IPv6 or IPv6 IPv4-mapped address: %#v", ifma)
                                continue
                        }
                        if ifma.IP.To4() != nil {
                                nmaf4++
-                       } else if ifma.IP.To16() != nil {
+                       }
+                       if ifma.IP.To16() != nil && ifma.IP.To4() == nil {
                                nmaf6++
                        }
                        t.Logf("joined group address %q", ifma.String())
index e25c1ed560b5f82a24682be0c5028c5dbc6a0157..4d6bcdf4c76a04bccce89bd589f1de21d0a8c3ca 100644 (file)
@@ -11,131 +11,103 @@ import (
        "unsafe"
 )
 
-func getAdapters() (*windows.IpAdapterAddresses, error) {
-       block := uint32(unsafe.Sizeof(windows.IpAdapterAddresses{}))
+// supportsVistaIP reports whether the platform implements new IP
+// stack and ABIs supported on Windows Vista and above.
+var supportsVistaIP bool
 
-       // pre-allocate a 15KB working buffer pointed to by the AdapterAddresses
-       // parameter.
-       // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).aspx
-       size := uint32(15000)
-
-       var addrs []windows.IpAdapterAddresses
-       for {
-               addrs = make([]windows.IpAdapterAddresses, size/block+1)
-               err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, &addrs[0], &size)
-               if err == nil {
-                       break
-               }
-               if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW {
-                       return nil, os.NewSyscallError("getadaptersaddresses", err)
-               }
-       }
-       return &addrs[0], nil
+func init() {
+       supportsVistaIP = probeWindowsIPStack()
 }
 
-func getInterfaceInfos() ([]syscall.InterfaceInfo, error) {
-       s, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
-       if err != nil {
-               return nil, err
-       }
-       defer closeFunc(s)
-
-       iia := [20]syscall.InterfaceInfo{}
-       ret := uint32(0)
-       size := uint32(unsafe.Sizeof(iia))
-       err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&iia[0])), size, &ret, nil, 0)
+func probeWindowsIPStack() (supportsVistaIP bool) {
+       v, err := syscall.GetVersion()
        if err != nil {
-               return nil, os.NewSyscallError("wsaioctl", err)
+               return true // Windows 10 and above will deprecate this API
        }
-       iilen := ret / uint32(unsafe.Sizeof(iia[0]))
-       return iia[:iilen-1], nil
-}
-
-func bytesEqualIP(a []byte, b []int8) bool {
-       for i := 0; i < len(a); i++ {
-               if a[i] != byte(b[i]) {
-                       return false
-               }
+       if byte(v) < 6 { // major version of Windows Vista is 6
+               return false
        }
        return true
 }
 
-func findInterfaceInfo(iis []syscall.InterfaceInfo, paddr *windows.IpAdapterAddresses) *syscall.InterfaceInfo {
-       for _, ii := range iis {
-               iaddr := (*syscall.RawSockaddr)(unsafe.Pointer(&ii.Address))
-               puni := paddr.FirstUnicastAddress
-               for ; puni != nil; puni = puni.Next {
-                       if iaddr.Family == puni.Address.Sockaddr.Addr.Family {
-                               switch iaddr.Family {
-                               case syscall.AF_INET:
-                                       a := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr
-                                       if bytesEqualIP(a[:], puni.Address.Sockaddr.Addr.Data[2:]) {
-                                               return &ii
-                                       }
-                               case syscall.AF_INET6:
-                                       a := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&ii.Address)).Addr
-                                       if bytesEqualIP(a[:], puni.Address.Sockaddr.Addr.Data[2:]) {
-                                               return &ii
-                                       }
-                               default:
-                                       continue
-                               }
+// adapterAddresses returns a list of IP adapter and address
+// structures. The structure contains an IP adapter and flattened
+// multiple IP addresses including unicast, anycast and multicast
+// addresses.
+func adapterAddresses() ([]*windows.IpAdapterAddresses, error) {
+       var b []byte
+       l := uint32(15000) // recommended initial size
+       for {
+               b = make([]byte, l)
+               err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l)
+               if err == nil {
+                       if l == 0 {
+                               return nil, nil
                        }
+                       break
                }
+               if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW {
+                       return nil, os.NewSyscallError("getadaptersaddresses", err)
+               }
+               if l <= uint32(len(b)) {
+                       return nil, os.NewSyscallError("getadaptersaddresses", err)
+               }
+       }
+       var aas []*windows.IpAdapterAddresses
+       for aa := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); aa != nil; aa = aa.Next {
+               aas = append(aas, aa)
        }
-       return nil
+       return aas, nil
 }
 
 // If the ifindex is zero, interfaceTable returns mappings of all
 // network interfaces.  Otherwise it returns a mapping of a specific
 // interface.
 func interfaceTable(ifindex int) ([]Interface, error) {
-       paddr, err := getAdapters()
-       if err != nil {
-               return nil, err
-       }
-
-       iis, err := getInterfaceInfos()
+       aas, err := adapterAddresses()
        if err != nil {
                return nil, err
        }
-
        var ift []Interface
-       for ; paddr != nil; paddr = paddr.Next {
-               index := paddr.IfIndex
-               if paddr.Ipv6IfIndex != 0 {
-                       index = paddr.Ipv6IfIndex
+       for _, aa := range aas {
+               index := aa.IfIndex
+               if index == 0 { // ipv6IfIndex is a substitute for ifIndex
+                       index = aa.Ipv6IfIndex
                }
                if ifindex == 0 || ifindex == int(index) {
-                       ii := findInterfaceInfo(iis, paddr)
-                       if ii == nil {
-                               continue
-                       }
-                       var flags Flags
-                       if paddr.Flags&windows.IfOperStatusUp != 0 {
-                               flags |= FlagUp
-                       }
-                       if paddr.IfType&windows.IF_TYPE_SOFTWARE_LOOPBACK != 0 {
-                               flags |= FlagLoopback
+                       ifi := Interface{
+                               Index: int(index),
+                               Name:  syscall.UTF16ToString((*(*[10000]uint16)(unsafe.Pointer(aa.FriendlyName)))[:]),
                        }
-                       if ii.Flags&syscall.IFF_BROADCAST != 0 {
-                               flags |= FlagBroadcast
+                       if aa.OperStatus == windows.IfOperStatusUp {
+                               ifi.Flags |= FlagUp
                        }
-                       if ii.Flags&syscall.IFF_POINTTOPOINT != 0 {
-                               flags |= FlagPointToPoint
+                       // For now we need to infer link-layer service
+                       // capabilities from media types.
+                       // We will be able to use
+                       // MIB_IF_ROW2.AccessType once we drop support
+                       // for Windows XP.
+                       switch aa.IfType {
+                       case windows.IF_TYPE_ETHERNET_CSMACD, windows.IF_TYPE_ISO88025_TOKENRING, windows.IF_TYPE_IEEE80211, windows.IF_TYPE_IEEE1394:
+                               ifi.Flags |= FlagBroadcast | FlagMulticast
+                       case windows.IF_TYPE_PPP, windows.IF_TYPE_TUNNEL:
+                               ifi.Flags |= FlagPointToPoint | FlagMulticast
+                       case windows.IF_TYPE_SOFTWARE_LOOPBACK:
+                               ifi.Flags |= FlagLoopback | FlagMulticast
+                       case windows.IF_TYPE_ATM:
+                               ifi.Flags |= FlagBroadcast | FlagPointToPoint | FlagMulticast // assume all services available; LANE, point-to-point and point-to-multipoint
                        }
-                       if ii.Flags&syscall.IFF_MULTICAST != 0 {
-                               flags |= FlagMulticast
+                       if aa.Mtu == 0xffffffff {
+                               ifi.MTU = -1
+                       } else {
+                               ifi.MTU = int(aa.Mtu)
                        }
-                       ifi := Interface{
-                               Index:        int(index),
-                               MTU:          int(paddr.Mtu),
-                               Name:         syscall.UTF16ToString((*(*[10000]uint16)(unsafe.Pointer(paddr.FriendlyName)))[:]),
-                               HardwareAddr: HardwareAddr(paddr.PhysicalAddress[:]),
-                               Flags:        flags,
+                       if aa.PhysicalAddressLength > 0 {
+                               ifi.HardwareAddr = make(HardwareAddr, aa.PhysicalAddressLength)
+                               copy(ifi.HardwareAddr, aa.PhysicalAddress[:])
                        }
                        ift = append(ift, ifi)
-                       if ifindex == int(ifi.Index) {
+                       if ifindex == ifi.Index {
                                break
                        }
                }
@@ -147,86 +119,150 @@ func interfaceTable(ifindex int) ([]Interface, error) {
 // network interfaces.  Otherwise it returns addresses for a specific
 // interface.
 func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
-       paddr, err := getAdapters()
+       aas, err := adapterAddresses()
        if err != nil {
                return nil, err
        }
-
        var ifat []Addr
-       for ; paddr != nil; paddr = paddr.Next {
-               index := paddr.IfIndex
-               if paddr.Ipv6IfIndex != 0 {
-                       index = paddr.Ipv6IfIndex
+       for _, aa := range aas {
+               index := aa.IfIndex
+               if index == 0 { // ipv6IfIndex is a substitute for ifIndex
+                       index = aa.Ipv6IfIndex
+               }
+               var pfx4, pfx6 []IPNet
+               if !supportsVistaIP {
+                       pfx4, pfx6, err = addrPrefixTable(aa)
+                       if err != nil {
+                               return nil, err
+                       }
                }
                if ifi == nil || ifi.Index == int(index) {
-                       puni := paddr.FirstUnicastAddress
-                       for ; puni != nil; puni = puni.Next {
-                               if sa, err := puni.Address.Sockaddr.Sockaddr(); err == nil {
-                                       switch sav := sa.(type) {
-                                       case *syscall.SockaddrInet4:
-                                               ifa := &IPNet{IP: make(IP, IPv4len), Mask: CIDRMask(int(puni.Address.SockaddrLength), 8*IPv4len)}
-                                               copy(ifa.IP, sav.Addr[:])
-                                               ifat = append(ifat, ifa)
-                                       case *syscall.SockaddrInet6:
-                                               ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(puni.Address.SockaddrLength), 8*IPv6len)}
-                                               copy(ifa.IP, sav.Addr[:])
-                                               ifat = append(ifat, ifa)
+                       for puni := aa.FirstUnicastAddress; puni != nil; puni = puni.Next {
+                               sa, err := puni.Address.Sockaddr.Sockaddr()
+                               if err != nil {
+                                       return nil, os.NewSyscallError("sockaddr", err)
+                               }
+                               var l int
+                               switch sa := sa.(type) {
+                               case *syscall.SockaddrInet4:
+                                       if supportsVistaIP {
+                                               l = int(puni.OnLinkPrefixLength)
+                                       } else {
+                                               l = addrPrefixLen(pfx4, IP(sa.Addr[:]))
                                        }
+                                       ifat = append(ifat, &IPNet{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]), Mask: CIDRMask(l, 8*IPv4len)})
+                               case *syscall.SockaddrInet6:
+                                       if supportsVistaIP {
+                                               l = int(puni.OnLinkPrefixLength)
+                                       } else {
+                                               l = addrPrefixLen(pfx6, IP(sa.Addr[:]))
+                                       }
+                                       ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(l, 8*IPv6len)}
+                                       copy(ifa.IP, sa.Addr[:])
+                                       ifat = append(ifat, ifa)
                                }
                        }
-                       pany := paddr.FirstAnycastAddress
-                       for ; pany != nil; pany = pany.Next {
-                               if sa, err := pany.Address.Sockaddr.Sockaddr(); err == nil {
-                                       switch sav := sa.(type) {
-                                       case *syscall.SockaddrInet4:
-                                               ifa := &IPNet{IP: make(IP, IPv4len), Mask: CIDRMask(int(pany.Address.SockaddrLength), 8*IPv4len)}
-                                               copy(ifa.IP, sav.Addr[:])
-                                               ifat = append(ifat, ifa)
-                                       case *syscall.SockaddrInet6:
-                                               ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(pany.Address.SockaddrLength), 8*IPv6len)}
-                                               copy(ifa.IP, sav.Addr[:])
-                                               ifat = append(ifat, ifa)
-                                       }
+                       for pany := aa.FirstAnycastAddress; pany != nil; pany = pany.Next {
+                               sa, err := pany.Address.Sockaddr.Sockaddr()
+                               if err != nil {
+                                       return nil, os.NewSyscallError("sockaddr", err)
+                               }
+                               switch sa := sa.(type) {
+                               case *syscall.SockaddrInet4:
+                                       ifat = append(ifat, &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])})
+                               case *syscall.SockaddrInet6:
+                                       ifa := &IPAddr{IP: make(IP, IPv6len)}
+                                       copy(ifa.IP, sa.Addr[:])
+                                       ifat = append(ifat, ifa)
                                }
                        }
                }
        }
-
        return ifat, nil
 }
 
+func addrPrefixTable(aa *windows.IpAdapterAddresses) (pfx4, pfx6 []IPNet, err error) {
+       for p := aa.FirstPrefix; p != nil; p = p.Next {
+               sa, err := p.Address.Sockaddr.Sockaddr()
+               if err != nil {
+                       return nil, nil, os.NewSyscallError("sockaddr", err)
+               }
+               switch sa := sa.(type) {
+               case *syscall.SockaddrInet4:
+                       pfx := IPNet{IP: IP(sa.Addr[:]), Mask: CIDRMask(int(p.PrefixLength), 8*IPv4len)}
+                       pfx4 = append(pfx4, pfx)
+               case *syscall.SockaddrInet6:
+                       pfx := IPNet{IP: IP(sa.Addr[:]), Mask: CIDRMask(int(p.PrefixLength), 8*IPv6len)}
+                       pfx6 = append(pfx6, pfx)
+               }
+       }
+       return
+}
+
+// addrPrefixLen returns an appropriate prefix length in bits for ip
+// from pfxs. It returns 32 or 128 when no appropriate on-link address
+// prefix found.
+//
+// NOTE: This is pretty naive implementation that contains many
+// allocations and non-effective linear search, and should not be used
+// freely.
+func addrPrefixLen(pfxs []IPNet, ip IP) int {
+       var l int
+       var cand *IPNet
+       for i := range pfxs {
+               if !pfxs[i].Contains(ip) {
+                       continue
+               }
+               if cand == nil {
+                       l, _ = pfxs[i].Mask.Size()
+                       cand = &pfxs[i]
+                       continue
+               }
+               m, _ := pfxs[i].Mask.Size()
+               if m > l {
+                       l = m
+                       cand = &pfxs[i]
+                       continue
+               }
+       }
+       if l > 0 {
+               return l
+       }
+       if ip.To4() != nil {
+               return 8 * IPv4len
+       }
+       return 8 * IPv6len
+}
+
 // interfaceMulticastAddrTable returns addresses for a specific
 // interface.
 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
-       paddr, err := getAdapters()
+       aas, err := adapterAddresses()
        if err != nil {
                return nil, err
        }
-
        var ifat []Addr
-       for ; paddr != nil; paddr = paddr.Next {
-               index := paddr.IfIndex
-               if paddr.Ipv6IfIndex != 0 {
-                       index = paddr.Ipv6IfIndex
+       for _, aa := range aas {
+               index := aa.IfIndex
+               if index == 0 { // ipv6IfIndex is a substitute for ifIndex
+                       index = aa.Ipv6IfIndex
                }
                if ifi == nil || ifi.Index == int(index) {
-                       pmul := paddr.FirstMulticastAddress
-                       for ; pmul != nil; pmul = pmul.Next {
-                               if sa, err := pmul.Address.Sockaddr.Sockaddr(); err == nil {
-                                       switch sav := sa.(type) {
-                                       case *syscall.SockaddrInet4:
-                                               ifa := &IPAddr{IP: make(IP, IPv4len)}
-                                               copy(ifa.IP, sav.Addr[:])
-                                               ifat = append(ifat, ifa)
-                                       case *syscall.SockaddrInet6:
-                                               ifa := &IPAddr{IP: make(IP, IPv6len)}
-                                               copy(ifa.IP, sav.Addr[:])
-                                               ifat = append(ifat, ifa)
-                                       }
+                       for pmul := aa.FirstMulticastAddress; pmul != nil; pmul = pmul.Next {
+                               sa, err := pmul.Address.Sockaddr.Sockaddr()
+                               if err != nil {
+                                       return nil, os.NewSyscallError("sockaddr", err)
+                               }
+                               switch sa := sa.(type) {
+                               case *syscall.SockaddrInet4:
+                                       ifat = append(ifat, &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])})
+                               case *syscall.SockaddrInet6:
+                                       ifa := &IPAddr{IP: make(IP, IPv6len)}
+                                       copy(ifa.IP, sa.Addr[:])
+                                       ifat = append(ifat, ifa)
                                }
                        }
                }
        }
-
        return ifat, nil
 }
diff --git a/libgo/go/net/interface_windows_test.go b/libgo/go/net/interface_windows_test.go
new file mode 100644 (file)
index 0000000..03f9168
--- /dev/null
@@ -0,0 +1,132 @@
+// Copyright 2015 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 (
+       "bytes"
+       "internal/syscall/windows"
+       "sort"
+       "testing"
+)
+
+func TestWindowsInterfaces(t *testing.T) {
+       aas, err := adapterAddresses()
+       if err != nil {
+               t.Fatal(err)
+       }
+       ift, err := Interfaces()
+       if err != nil {
+               t.Fatal(err)
+       }
+       for i, ifi := range ift {
+               aa := aas[i]
+               if len(ifi.HardwareAddr) != int(aa.PhysicalAddressLength) {
+                       t.Errorf("got %d; want %d", len(ifi.HardwareAddr), aa.PhysicalAddressLength)
+               }
+               if ifi.MTU > 0x7fffffff {
+                       t.Errorf("%s: got %d; want less than or equal to 1<<31 - 1", ifi.Name, ifi.MTU)
+               }
+               if ifi.Flags&FlagUp != 0 && aa.OperStatus != windows.IfOperStatusUp {
+                       t.Errorf("%s: got %v; should not include FlagUp", ifi.Name, ifi.Flags)
+               }
+               if ifi.Flags&FlagLoopback != 0 && aa.IfType != windows.IF_TYPE_SOFTWARE_LOOPBACK {
+                       t.Errorf("%s: got %v; should not include FlagLoopback", ifi.Name, ifi.Flags)
+               }
+               if _, _, err := addrPrefixTable(aa); err != nil {
+                       t.Errorf("%s: %v", ifi.Name, err)
+               }
+       }
+}
+
+type byAddrLen []IPNet
+
+func (ps byAddrLen) Len() int { return len(ps) }
+
+func (ps byAddrLen) Less(i, j int) bool {
+       if n := bytes.Compare(ps[i].IP, ps[j].IP); n != 0 {
+               return n < 0
+       }
+       if n := bytes.Compare(ps[i].Mask, ps[j].Mask); n != 0 {
+               return n < 0
+       }
+       return false
+}
+
+func (ps byAddrLen) Swap(i, j int) { ps[i], ps[j] = ps[j], ps[i] }
+
+var windowsAddrPrefixLenTests = []struct {
+       pfxs []IPNet
+       ip   IP
+       out  int
+}{
+       {
+               []IPNet{
+                       {IP: IPv4(172, 16, 0, 0), Mask: IPv4Mask(255, 255, 0, 0)},
+                       {IP: IPv4(192, 168, 0, 0), Mask: IPv4Mask(255, 255, 255, 0)},
+                       {IP: IPv4(192, 168, 0, 0), Mask: IPv4Mask(255, 255, 255, 128)},
+                       {IP: IPv4(192, 168, 0, 0), Mask: IPv4Mask(255, 255, 255, 192)},
+               },
+               IPv4(192, 168, 0, 1),
+               26,
+       },
+       {
+               []IPNet{
+                       {IP: ParseIP("2001:db8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0"))},
+                       {IP: ParseIP("2001:db8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff8"))},
+                       {IP: ParseIP("2001:db8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc"))},
+               },
+               ParseIP("2001:db8::1"),
+               126,
+       },
+
+       // Fallback cases. It may happen on Windows XP or 2003 server.
+       {
+               []IPNet{
+                       {IP: IPv4(127, 0, 0, 0).To4(), Mask: IPv4Mask(255, 0, 0, 0)},
+                       {IP: IPv4(10, 0, 0, 0).To4(), Mask: IPv4Mask(255, 0, 0, 0)},
+                       {IP: IPv4(172, 16, 0, 0).To4(), Mask: IPv4Mask(255, 255, 0, 0)},
+                       {IP: IPv4(192, 168, 255, 0), Mask: IPv4Mask(255, 255, 255, 0)},
+                       {IP: IPv4zero, Mask: IPv4Mask(0, 0, 0, 0)},
+               },
+               IPv4(192, 168, 0, 1),
+               8 * IPv4len,
+       },
+       {
+               nil,
+               IPv4(192, 168, 0, 1),
+               8 * IPv4len,
+       },
+       {
+               []IPNet{
+                       {IP: IPv6loopback, Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))},
+                       {IP: ParseIP("2001:db8:1::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0"))},
+                       {IP: ParseIP("2001:db8:2::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff8"))},
+                       {IP: ParseIP("2001:db8:3::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc"))},
+                       {IP: IPv6unspecified, Mask: IPMask(ParseIP("::"))},
+               },
+               ParseIP("2001:db8::1"),
+               8 * IPv6len,
+       },
+       {
+               nil,
+               ParseIP("2001:db8::1"),
+               8 * IPv6len,
+       },
+}
+
+func TestWindowsAddrPrefixLen(t *testing.T) {
+       for i, tt := range windowsAddrPrefixLenTests {
+               sort.Sort(byAddrLen(tt.pfxs))
+               l := addrPrefixLen(tt.pfxs, tt.ip)
+               if l != tt.out {
+                       t.Errorf("#%d: got %d; want %d", i, l, tt.out)
+               }
+               sort.Sort(sort.Reverse(byAddrLen(tt.pfxs)))
+               l = addrPrefixLen(tt.pfxs, tt.ip)
+               if l != tt.out {
+                       t.Errorf("#%d: got %d; want %d", i, l, tt.out)
+               }
+       }
+}
index 4e38c7a85f3aa68009735204f6ef8c03718d5151..8bef06b97c873fe08dbf28eaa4554b4295419c7a 100644 (file)
@@ -77,7 +77,7 @@ type Status struct {
 }
 
 func (so Status) String() string {
-       return fmt.Sprintf("(%s, %s, %s): syscallerr=%v, socketerr=%v", familyString(so.Cookie.Family()), typeString(so.Cookie.Type()), protocolString(so.Cookie.Protocol()), so.Err, so.SocketErr)
+       return fmt.Sprintf("(%s, %s, %s): syscallerr=%v socketerr=%v", familyString(so.Cookie.Family()), typeString(so.Cookie.Type()), protocolString(so.Cookie.Protocol()), so.Err, so.SocketErr)
 }
 
 // A Stat represents a per-cookie socket statistics.
@@ -100,7 +100,7 @@ type Stat struct {
 }
 
 func (st Stat) String() string {
-       return fmt.Sprintf("(%s, %s, %s): opened=%d, connected=%d, listened=%d, accepted=%d, closed=%d, openfailed=%d, connectfailed=%d, listenfailed=%d, acceptfailed=%d, closefailed=%d", familyString(st.Family), typeString(st.Type), protocolString(st.Protocol), st.Opened, st.Connected, st.Listened, st.Accepted, st.Closed, st.OpenFailed, st.ConnectFailed, st.ListenFailed, st.AcceptFailed, st.CloseFailed)
+       return fmt.Sprintf("(%s, %s, %s): opened=%d connected=%d listened=%d accepted=%d closed=%d openfailed=%d connectfailed=%d listenfailed=%d acceptfailed=%d closefailed=%d", familyString(st.Family), typeString(st.Type), protocolString(st.Protocol), st.Opened, st.Connected, st.Listened, st.Accepted, st.Closed, st.OpenFailed, st.ConnectFailed, st.ListenFailed, st.AcceptFailed, st.CloseFailed)
 }
 
 type stats map[Cookie]*Stat
index 9417606ce9487464ee91a217b62b01b8db2596bc..93fee3e232e114d3236196e3ef570b86497474c2 100644 (file)
@@ -220,7 +220,7 @@ func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn,
        if raddr == nil {
                return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
        }
-       fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_RAW, proto, "dial")
+       fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_RAW, proto, "dial", noCancel)
        if err != nil {
                return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
        }
@@ -241,7 +241,7 @@ func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
        default:
                return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(netProto)}
        }
-       fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_RAW, proto, "listen")
+       fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_RAW, proto, "listen", noCancel)
        if err != nil {
                return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: err}
        }
index 6e75c33d53471e91fa276736a91420bab316497e..55f697f622ed6d355a3a3d899510fb474a438c94 100644 (file)
@@ -213,7 +213,7 @@ func internetAddrList(net, addr string, deadline time.Time) (addrList, error) {
                        if host, port, err = SplitHostPort(addr); err != nil {
                                return nil, err
                        }
-                       if portnum, err = parsePort(net, port); err != nil {
+                       if portnum, err = LookupPort(net, port); err != nil {
                                return nil, err
                        }
                }
index 83eaf855b4c2d07e125463966f7e792be826e119..2bddd46a156e5bbc10f2f9c45a029e4d7b106e9d 100644 (file)
@@ -101,10 +101,11 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 //
 //     1. A wild-wild listen, "tcp" + ""
 //     If the platform supports both IPv6 and IPv6 IPv4-mapping
-//     capabilities, we assume that the user want to listen on
-//     both IPv4 and IPv6 wildcard address over an AF_INET6
-//     socket with IPV6_V6ONLY=0.  Otherwise we prefer an IPv4
-//     wildcard address listen over an AF_INET socket.
+//     capabilities, or does not support IPv4, we assume that
+//     the user wants to listen on both IPv4 and IPv6 wildcard
+//     addresses over an AF_INET6 socket with IPV6_V6ONLY=0.
+//     Otherwise we prefer an IPv4 wildcard address listen over
+//     an AF_INET socket.
 //
 //     2. A wild-ipv4wild listen, "tcp" + "0.0.0.0"
 //     Same as 1.
@@ -137,7 +138,7 @@ func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family
        }
 
        if mode == "listen" && (laddr == nil || laddr.isWildcard()) {
-               if supportsIPv4map {
+               if supportsIPv4map || !supportsIPv4 {
                        return syscall.AF_INET6, false
                }
                if laddr == nil {
@@ -155,9 +156,9 @@ func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family
 
 // Internet sockets (TCP, UDP, IP)
 
-func internetSocket(net string, laddr, raddr sockaddr, deadline time.Time, sotype, proto int, mode string) (fd *netFD, err error) {
+func internetSocket(net string, laddr, raddr sockaddr, deadline time.Time, sotype, proto int, mode string, cancel <-chan struct{}) (fd *netFD, err error) {
        family, ipv6only := favoriteAddrFamily(net, laddr, raddr, mode)
-       return socket(net, family, sotype, proto, ipv6only, laddr, raddr, deadline)
+       return socket(net, family, sotype, proto, ipv6only, laddr, raddr, deadline, cancel)
 }
 
 func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, error) {
index 9008322dc5a76fd9a401e6e08fb181b8a9d4a99a..7aa111ba929b864802b268c60140ef5185487c11 100644 (file)
@@ -123,10 +123,22 @@ func lookupIPDeadline(host string, deadline time.Time) (addrs []IPAddr, err erro
 
 // LookupPort looks up the port for the given network and service.
 func LookupPort(network, service string) (port int, err error) {
-       if n, i, ok := dtoi(service, 0); ok && i == len(service) {
-               return n, nil
+       if service == "" {
+               // Lock in the legacy behavior that an empty string
+               // means port 0. See Issue 13610.
+               return 0, nil
        }
-       return lookupPort(network, service)
+       port, _, ok := dtoi(service, 0)
+       if !ok && port != big && port != -big {
+               port, err = lookupPort(network, service)
+               if err != nil {
+                       return 0, err
+               }
+       }
+       if 0 > port || port > 65535 {
+               return 0, &AddrError{Err: "invalid port", Addr: service}
+       }
+       return port, nil
 }
 
 // LookupCNAME returns the canonical DNS host for the given name.
index c6274640bb7d251434f093474a1f4c65661202a4..a33162882b7deeaea594a48f0e82b8c3ea899056 100644 (file)
@@ -225,8 +225,8 @@ func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err
                if !(portOk && priorityOk && weightOk) {
                        continue
                }
-               addrs = append(addrs, &SRV{f[5], uint16(port), uint16(priority), uint16(weight)})
-               cname = f[0]
+               addrs = append(addrs, &SRV{absDomainName([]byte(f[5])), uint16(port), uint16(priority), uint16(weight)})
+               cname = absDomainName([]byte(f[0]))
        }
        byPriorityWeight(addrs).sort()
        return
@@ -243,7 +243,7 @@ func lookupMX(name string) (mx []*MX, err error) {
                        continue
                }
                if pref, _, ok := dtoi(f[2], 0); ok {
-                       mx = append(mx, &MX{f[3], uint16(pref)})
+                       mx = append(mx, &MX{absDomainName([]byte(f[3])), uint16(pref)})
                }
        }
        byPref(mx).sort()
@@ -260,7 +260,7 @@ func lookupNS(name string) (ns []*NS, err error) {
                if len(f) < 3 {
                        continue
                }
-               ns = append(ns, &NS{f[2]})
+               ns = append(ns, &NS{absDomainName([]byte(f[2]))})
        }
        return
 }
@@ -272,7 +272,7 @@ func lookupTXT(name string) (txt []string, err error) {
        }
        for _, line := range lines {
                if i := byteIndex(line, '\t'); i >= 0 {
-                       txt = append(txt, line[i+1:])
+                       txt = append(txt, absDomainName([]byte(line[i+1:])))
                }
        }
        return
@@ -292,7 +292,7 @@ func lookupAddr(addr string) (name []string, err error) {
                if len(f) < 3 {
                        continue
                }
-               name = append(name, f[2])
+               name = append(name, absDomainName([]byte(f[2])))
        }
        return
 }
index 86957b557566e64c42d604da6d4242149baa3975..439496ac81d2620383c42df07cb7549d9e8299ec 100644 (file)
@@ -7,6 +7,8 @@ package net
 import (
        "bytes"
        "fmt"
+       "internal/testenv"
+       "runtime"
        "strings"
        "testing"
        "time"
@@ -37,26 +39,26 @@ var lookupGoogleSRVTests = []struct {
 }{
        {
                "xmpp-server", "tcp", "google.com",
-               "google.com", "google.com",
+               "google.com.", "google.com.",
        },
        {
                "xmpp-server", "tcp", "google.com.",
-               "google.com", "google.com",
+               "google.com.", "google.com.",
        },
 
        // non-standard back door
        {
                "", "", "_xmpp-server._tcp.google.com",
-               "google.com", "google.com",
+               "google.com.", "google.com.",
        },
        {
                "", "", "_xmpp-server._tcp.google.com.",
-               "google.com", "google.com",
+               "google.com.", "google.com.",
        },
 }
 
 func TestLookupGoogleSRV(t *testing.T) {
-       if testing.Short() || !*testExternal {
+       if testing.Short() && testenv.Builder() == "" || !*testExternal {
                t.Skip("avoid external network")
        }
        if !supportsIPv4 || !*testIPv4 {
@@ -71,11 +73,11 @@ func TestLookupGoogleSRV(t *testing.T) {
                if len(srvs) == 0 {
                        t.Error("got no record")
                }
-               if !strings.HasSuffix(cname, tt.cname) && !strings.HasSuffix(cname, tt.cname+".") {
+               if !strings.HasSuffix(cname, tt.cname) {
                        t.Errorf("got %s; want %s", cname, tt.cname)
                }
                for _, srv := range srvs {
-                       if !strings.HasSuffix(srv.Target, tt.target) && !strings.HasSuffix(srv.Target, tt.target+".") {
+                       if !strings.HasSuffix(srv.Target, tt.target) {
                                t.Errorf("got %v; want a record containing %s", srv, tt.target)
                        }
                }
@@ -85,12 +87,12 @@ func TestLookupGoogleSRV(t *testing.T) {
 var lookupGmailMXTests = []struct {
        name, host string
 }{
-       {"gmail.com", "google.com"},
-       {"gmail.com.", "google.com"},
+       {"gmail.com", "google.com."},
+       {"gmail.com.", "google.com."},
 }
 
 func TestLookupGmailMX(t *testing.T) {
-       if testing.Short() || !*testExternal {
+       if testing.Short() && testenv.Builder() == "" || !*testExternal {
                t.Skip("avoid external network")
        }
        if !supportsIPv4 || !*testIPv4 {
@@ -106,7 +108,7 @@ func TestLookupGmailMX(t *testing.T) {
                        t.Error("got no record")
                }
                for _, mx := range mxs {
-                       if !strings.HasSuffix(mx.Host, tt.host) && !strings.HasSuffix(mx.Host, tt.host+".") {
+                       if !strings.HasSuffix(mx.Host, tt.host) {
                                t.Errorf("got %v; want a record containing %s", mx, tt.host)
                        }
                }
@@ -116,12 +118,12 @@ func TestLookupGmailMX(t *testing.T) {
 var lookupGmailNSTests = []struct {
        name, host string
 }{
-       {"gmail.com", "google.com"},
-       {"gmail.com.", "google.com"},
+       {"gmail.com", "google.com."},
+       {"gmail.com.", "google.com."},
 }
 
 func TestLookupGmailNS(t *testing.T) {
-       if testing.Short() || !*testExternal {
+       if testing.Short() && testenv.Builder() == "" || !*testExternal {
                t.Skip("avoid external network")
        }
        if !supportsIPv4 || !*testIPv4 {
@@ -137,7 +139,7 @@ func TestLookupGmailNS(t *testing.T) {
                        t.Error("got no record")
                }
                for _, ns := range nss {
-                       if !strings.HasSuffix(ns.Host, tt.host) && !strings.HasSuffix(ns.Host, tt.host+".") {
+                       if !strings.HasSuffix(ns.Host, tt.host) {
                                t.Errorf("got %v; want a record containing %s", ns, tt.host)
                        }
                }
@@ -152,7 +154,7 @@ var lookupGmailTXTTests = []struct {
 }
 
 func TestLookupGmailTXT(t *testing.T) {
-       if testing.Short() || !*testExternal {
+       if testing.Short() && testenv.Builder() == "" || !*testExternal {
                t.Skip("avoid external network")
        }
        if !supportsIPv4 || !*testIPv4 {
@@ -178,14 +180,15 @@ func TestLookupGmailTXT(t *testing.T) {
 var lookupGooglePublicDNSAddrTests = []struct {
        addr, name string
 }{
-       {"8.8.8.8", ".google.com"},
-       {"8.8.4.4", ".google.com"},
-       {"2001:4860:4860::8888", ".google.com"},
-       {"2001:4860:4860::8844", ".google.com"},
+       {"8.8.8.8", ".google.com."},
+       {"8.8.4.4", ".google.com."},
+
+       {"2001:4860:4860::8888", ".google.com."},
+       {"2001:4860:4860::8844", ".google.com."},
 }
 
 func TestLookupGooglePublicDNSAddr(t *testing.T) {
-       if testing.Short() || !*testExternal {
+       if testing.Short() && testenv.Builder() == "" || !*testExternal {
                t.Skip("avoid external network")
        }
        if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
@@ -201,22 +204,46 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) {
                        t.Error("got no record")
                }
                for _, name := range names {
-                       if !strings.HasSuffix(name, tt.name) && !strings.HasSuffix(name, tt.name+".") {
+                       if !strings.HasSuffix(name, tt.name) {
                                t.Errorf("got %s; want a record containing %s", name, tt.name)
                        }
                }
        }
 }
 
+func TestLookupIPv6LinkLocalAddr(t *testing.T) {
+       if !supportsIPv6 || !*testIPv6 {
+               t.Skip("IPv6 is required")
+       }
+
+       addrs, err := LookupHost("localhost")
+       if err != nil {
+               t.Fatal(err)
+       }
+       found := false
+       for _, addr := range addrs {
+               if addr == "fe80::1%lo0" {
+                       found = true
+                       break
+               }
+       }
+       if !found {
+               t.Skipf("not supported on %s", runtime.GOOS)
+       }
+       if _, err := LookupAddr("fe80::1%lo0"); err != nil {
+               t.Error(err)
+       }
+}
+
 var lookupIANACNAMETests = []struct {
        name, cname string
 }{
-       {"www.iana.org", "icann.org"},
-       {"www.iana.org.", "icann.org"},
+       {"www.iana.org", "icann.org."},
+       {"www.iana.org.", "icann.org."},
 }
 
 func TestLookupIANACNAME(t *testing.T) {
-       if testing.Short() || !*testExternal {
+       if testing.Short() && testenv.Builder() == "" || !*testExternal {
                t.Skip("avoid external network")
        }
        if !supportsIPv4 || !*testIPv4 {
@@ -228,7 +255,7 @@ func TestLookupIANACNAME(t *testing.T) {
                if err != nil {
                        t.Fatal(err)
                }
-               if !strings.HasSuffix(cname, tt.cname) && !strings.HasSuffix(cname, tt.cname+".") {
+               if !strings.HasSuffix(cname, tt.cname) {
                        t.Errorf("got %s; want a record containing %s", cname, tt.cname)
                }
        }
@@ -242,7 +269,7 @@ var lookupGoogleHostTests = []struct {
 }
 
 func TestLookupGoogleHost(t *testing.T) {
-       if testing.Short() || !*testExternal {
+       if testing.Short() && testenv.Builder() == "" || !*testExternal {
                t.Skip("avoid external network")
        }
        if !supportsIPv4 || !*testIPv4 {
@@ -273,7 +300,7 @@ var lookupGoogleIPTests = []struct {
 }
 
 func TestLookupGoogleIP(t *testing.T) {
-       if testing.Short() || !*testExternal {
+       if testing.Short() && testenv.Builder() == "" || !*testExternal {
                t.Skip("avoid external network")
        }
        if !supportsIPv4 || !*testIPv4 {
@@ -394,17 +421,62 @@ func TestLookupIPDeadline(t *testing.T) {
        t.Logf("%v succeeded, %v failed (%v timeout, %v temporary, %v other, %v unknown)", qstats.succeeded, qstats.failed, qstats.timeout, qstats.temporary, qstats.other, qstats.unknown)
 }
 
-func TestLookupDots(t *testing.T) {
-       if testing.Short() || !*testExternal {
-               t.Skipf("skipping external network test")
+func TestLookupDotsWithLocalSource(t *testing.T) {
+       if !supportsIPv4 || !*testIPv4 {
+               t.Skip("IPv4 is required")
        }
 
-       fixup := forceGoDNS()
-       defer fixup()
-       testDots(t, "go")
+       for i, fn := range []func() func(){forceGoDNS, forceCgoDNS} {
+               fixup := fn()
+               if fixup == nil {
+                       continue
+               }
+               names, err := LookupAddr("127.0.0.1")
+               fixup()
+               if err != nil {
+                       t.Logf("#%d: %v", i, err)
+                       continue
+               }
+               mode := "netgo"
+               if i == 1 {
+                       mode = "netcgo"
+               }
+       loop:
+               for i, name := range names {
+                       if strings.Index(name, ".") == len(name)-1 { // "localhost" not "localhost."
+                               for j := range names {
+                                       if j == i {
+                                               continue
+                                       }
+                                       if names[j] == name[:len(name)-1] {
+                                               // It's OK if we find the name without the dot,
+                                               // as some systems say 127.0.0.1 localhost localhost.
+                                               continue loop
+                                       }
+                               }
+                               t.Errorf("%s: got %s; want %s", mode, name, name[:len(name)-1])
+                       } else if strings.Contains(name, ".") && !strings.HasSuffix(name, ".") { // "localhost.localdomain." not "localhost.localdomain"
+                               t.Errorf("%s: got %s; want name ending with trailing dot", mode, name)
+                       }
+               }
+       }
+}
+
+func TestLookupDotsWithRemoteSource(t *testing.T) {
+       if testing.Short() && testenv.Builder() == "" || !*testExternal {
+               t.Skip("avoid external network")
+       }
+       if !supportsIPv4 || !*testIPv4 {
+               t.Skip("IPv4 is required")
+       }
 
-       if forceCgoDNS() {
+       if fixup := forceGoDNS(); fixup != nil {
+               testDots(t, "go")
+               fixup()
+       }
+       if fixup := forceCgoDNS(); fixup != nil {
                testDots(t, "cgo")
+               fixup()
        }
 }
 
@@ -501,3 +573,62 @@ func srvString(srvs []*SRV) string {
        fmt.Fprintf(&buf, "]")
        return buf.String()
 }
+
+var lookupPortTests = []struct {
+       network string
+       name    string
+       port    int
+       ok      bool
+}{
+       {"tcp", "0", 0, true},
+       {"tcp", "echo", 7, true},
+       {"tcp", "discard", 9, true},
+       {"tcp", "systat", 11, true},
+       {"tcp", "daytime", 13, true},
+       {"tcp", "chargen", 19, true},
+       {"tcp", "ftp-data", 20, true},
+       {"tcp", "ftp", 21, true},
+       {"tcp", "telnet", 23, true},
+       {"tcp", "smtp", 25, true},
+       {"tcp", "time", 37, true},
+       {"tcp", "domain", 53, true},
+       {"tcp", "finger", 79, true},
+       {"tcp", "42", 42, true},
+
+       {"udp", "0", 0, true},
+       {"udp", "echo", 7, true},
+       {"udp", "tftp", 69, true},
+       {"udp", "bootpc", 68, true},
+       {"udp", "bootps", 67, true},
+       {"udp", "domain", 53, true},
+       {"udp", "ntp", 123, true},
+       {"udp", "snmp", 161, true},
+       {"udp", "syslog", 514, true},
+       {"udp", "42", 42, true},
+
+       {"--badnet--", "zzz", 0, false},
+       {"tcp", "--badport--", 0, false},
+       {"tcp", "-1", 0, false},
+       {"tcp", "65536", 0, false},
+       {"udp", "-1", 0, false},
+       {"udp", "65536", 0, false},
+
+       // Issue 13610: LookupPort("tcp", "")
+       {"tcp", "", 0, true},
+       {"tcp6", "", 0, true},
+       {"tcp4", "", 0, true},
+       {"udp", "", 0, true},
+}
+
+func TestLookupPort(t *testing.T) {
+       switch runtime.GOOS {
+       case "nacl":
+               t.Skipf("not supported on %s", runtime.GOOS)
+       }
+
+       for _, tt := range lookupPortTests {
+               if port, err := LookupPort(tt.network, tt.name); port != tt.port || (err == nil) != tt.ok {
+                       t.Errorf("LookupPort(%q, %q) = %d, %v; want %d", tt.network, tt.name, port, err, tt.port)
+               }
+       }
+}
index 1b6d392f660c8e1b7a98fbe9663de70715d054a6..13edc264e82a59006112b6edc5fd6a8cb4ef16fd 100644 (file)
@@ -19,7 +19,7 @@ var (
 func getprotobyname(name string) (proto int, err error) {
        p, err := syscall.GetProtoByName(name)
        if err != nil {
-               return 0, os.NewSyscallError("getorotobyname", err)
+               return 0, os.NewSyscallError("getprotobyname", err)
        }
        return int(p.Proto), nil
 }
@@ -221,10 +221,7 @@ func lookupCNAME(name string) (string, error) {
        // windows returns DNS_INFO_NO_RECORDS if there are no CNAME-s
        if errno, ok := e.(syscall.Errno); ok && errno == syscall.DNS_INFO_NO_RECORDS {
                // if there are no aliases, the canonical name is the input name
-               if name == "" || name[len(name)-1] != '.' {
-                       return name + ".", nil
-               }
-               return name, nil
+               return absDomainName([]byte(name)), nil
        }
        if e != nil {
                return "", &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
@@ -232,8 +229,8 @@ func lookupCNAME(name string) (string, error) {
        defer syscall.DnsRecordListFree(r, 1)
 
        resolved := resolveCNAME(syscall.StringToUTF16Ptr(name), r)
-       cname := syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(resolved))[:]) + "."
-       return cname, nil
+       cname := syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(resolved))[:])
+       return absDomainName([]byte(cname)), nil
 }
 
 func lookupSRV(service, proto, name string) (string, []*SRV, error) {
@@ -255,10 +252,10 @@ func lookupSRV(service, proto, name string) (string, []*SRV, error) {
        srvs := make([]*SRV, 0, 10)
        for _, p := range validRecs(r, syscall.DNS_TYPE_SRV, target) {
                v := (*syscall.DNSSRVData)(unsafe.Pointer(&p.Data[0]))
-               srvs = append(srvs, &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight})
+               srvs = append(srvs, &SRV{absDomainName([]byte(syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]))), v.Port, v.Priority, v.Weight})
        }
        byPriorityWeight(srvs).sort()
-       return name, srvs, nil
+       return absDomainName([]byte(target)), srvs, nil
 }
 
 func lookupMX(name string) ([]*MX, error) {
@@ -274,7 +271,7 @@ func lookupMX(name string) ([]*MX, error) {
        mxs := make([]*MX, 0, 10)
        for _, p := range validRecs(r, syscall.DNS_TYPE_MX, name) {
                v := (*syscall.DNSMXData)(unsafe.Pointer(&p.Data[0]))
-               mxs = append(mxs, &MX{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.NameExchange))[:]) + ".", v.Preference})
+               mxs = append(mxs, &MX{absDomainName([]byte(syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.NameExchange))[:]))), v.Preference})
        }
        byPref(mxs).sort()
        return mxs, nil
@@ -293,7 +290,7 @@ func lookupNS(name string) ([]*NS, error) {
        nss := make([]*NS, 0, 10)
        for _, p := range validRecs(r, syscall.DNS_TYPE_NS, name) {
                v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
-               nss = append(nss, &NS{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]) + "."})
+               nss = append(nss, &NS{absDomainName([]byte(syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:])))})
        }
        return nss, nil
 }
@@ -336,7 +333,7 @@ func lookupAddr(addr string) ([]string, error) {
        ptrs := make([]string, 0, 10)
        for _, p := range validRecs(r, syscall.DNS_TYPE_PTR, arpa) {
                v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
-               ptrs = append(ptrs, syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]))
+               ptrs = append(ptrs, absDomainName([]byte(syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]))))
        }
        return ptrs, nil
 }
index 8594a9146ae681772e1cbc1f5032d03eab2d0278..93f0b091219889ed337fb2b33e815e0a21048ce6 100644 (file)
@@ -24,14 +24,17 @@ func (a HardwareAddr) String() string {
        return string(buf)
 }
 
-// ParseMAC parses s as an IEEE 802 MAC-48, EUI-48, or EUI-64 using one of the
-// following formats:
+// ParseMAC parses s as an IEEE 802 MAC-48, EUI-48, EUI-64, or a 20-octet
+// IP over InfiniBand link-layer address using one of the following formats:
 //   01:23:45:67:89:ab
 //   01:23:45:67:89:ab:cd:ef
+//   01:23:45:67:89:ab:cd:ef:00:00:01:23:45:67:89:ab:cd:ef:00:00
 //   01-23-45-67-89-ab
 //   01-23-45-67-89-ab-cd-ef
+//   01-23-45-67-89-ab-cd-ef-00-00-01-23-45-67-89-ab-cd-ef-00-00
 //   0123.4567.89ab
 //   0123.4567.89ab.cdef
+//   0123.4567.89ab.cdef.0000.0123.4567.89ab.cdef.0000
 func ParseMAC(s string) (hw HardwareAddr, err error) {
        if len(s) < 14 {
                goto error
@@ -42,7 +45,7 @@ func ParseMAC(s string) (hw HardwareAddr, err error) {
                        goto error
                }
                n := (len(s) + 1) / 3
-               if n != 6 && n != 8 {
+               if n != 6 && n != 8 && n != 20 {
                        goto error
                }
                hw = make(HardwareAddr, n)
@@ -58,7 +61,7 @@ func ParseMAC(s string) (hw HardwareAddr, err error) {
                        goto error
                }
                n := 2 * (len(s) + 1) / 5
-               if n != 6 && n != 8 {
+               if n != 6 && n != 8 && n != 20 {
                        goto error
                }
                hw = make(HardwareAddr, n)
index 0af0c014f50736081268014ad42a6b7b075f0a14..1ec6b287ac3a4062299141657a83956a9110eaca 100644 (file)
@@ -34,6 +34,30 @@ var parseMACTests = []struct {
        {"01:23:45:67:89:AB:CD:EF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""},
        {"01-23-45-67-89-AB-CD-EF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""},
        {"0123.4567.89AB.CDEF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""},
+       {
+               "01:23:45:67:89:ab:cd:ef:00:00:01:23:45:67:89:ab:cd:ef:00:00",
+               HardwareAddr{
+                       0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x00, 0x00,
+                       0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x00, 0x00,
+               },
+               "",
+       },
+       {
+               "01-23-45-67-89-ab-cd-ef-00-00-01-23-45-67-89-ab-cd-ef-00-00",
+               HardwareAddr{
+                       0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x00, 0x00,
+                       0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x00, 0x00,
+               },
+               "",
+       },
+       {
+               "0123.4567.89ab.cdef.0000.0123.4567.89ab.cdef.0000",
+               HardwareAddr{
+                       0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x00, 0x00,
+                       0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x00, 0x00,
+               },
+               "",
+       },
 }
 
 func TestParseMAC(t *testing.T) {
index 266ac50a38dee1b82b8effbdc65b90a4dc008a64..923630c49ce02143309c00365afcb04d2b401ac7 100644 (file)
@@ -234,6 +234,12 @@ func (a *Address) String() string {
                return b.String()
        }
 
+       // Text in an encoded-word in a display-name must not contain certain
+       // characters like quotes or parentheses (see RFC 2047 section 5.3).
+       // When this is the case encode the name using base64 encoding.
+       if strings.ContainsAny(a.Name, "\"#$%&'(),.:;<>@[]^`{|}~") {
+               return mime.BEncoding.Encode("utf-8", a.Name) + " " + s
+       }
        return mime.QEncoding.Encode("utf-8", a.Name) + " " + s
 }
 
@@ -386,10 +392,9 @@ func (p *addrParser) consumePhrase() (phrase string, err error) {
                        // We actually parse dot-atom here to be more permissive
                        // than what RFC 5322 specifies.
                        word, err = p.consumeAtom(true, true)
-               }
-
-               if err == nil {
-                       word, err = p.decodeRFC2047Word(word)
+                       if err == nil {
+                               word, err = p.decodeRFC2047Word(word)
+                       }
                }
 
                if err != nil {
@@ -442,17 +447,25 @@ Loop:
        return string(qsb), nil
 }
 
+var errNonASCII = errors.New("mail: unencoded non-ASCII text in address")
+
 // consumeAtom parses an RFC 5322 atom at the start of p.
 // If dot is true, consumeAtom parses an RFC 5322 dot-atom instead.
 // If permissive is true, consumeAtom will not fail on
 // leading/trailing/double dots in the atom (see golang.org/issue/4938).
 func (p *addrParser) consumeAtom(dot bool, permissive bool) (atom string, err error) {
-       if !isAtext(p.peek(), false) {
+       if c := p.peek(); !isAtext(c, false) {
+               if c > 127 {
+                       return "", errNonASCII
+               }
                return "", errors.New("mail: invalid string")
        }
        i := 1
        for ; i < p.len() && isAtext(p.s[i], dot); i++ {
        }
+       if i < p.len() && p.s[i] > 127 {
+               return "", errNonASCII
+       }
        atom, p.s = string(p.s[:i]), p.s[i:]
        if !permissive {
                if strings.HasPrefix(atom, ".") {
index 1b422743f95fb4656265d5695529dee0ae6757c9..4e718e2636727454ca901ef71aee450954988284 100644 (file)
@@ -127,6 +127,14 @@ func TestAddressParsingError(t *testing.T) {
        }
 }
 
+func TestAddressParsingErrorUnquotedNonASCII(t *testing.T) {
+       const txt = "µ <micro@example.net>"
+       _, err := ParseAddress(txt)
+       if err == nil || !strings.Contains(err.Error(), "unencoded non-ASCII text in address") {
+               t.Errorf(`mail.ParseAddress(%q) err: %q, want ".*unencoded non-ASCII text in address.*"`, txt, err)
+       }
+}
+
 func TestAddressParsing(t *testing.T) {
        tests := []struct {
                addrsStr string
@@ -449,7 +457,7 @@ func TestAddressParser(t *testing.T) {
        }
 }
 
-func TestAddressFormatting(t *testing.T) {
+func TestAddressString(t *testing.T) {
        tests := []struct {
                addr *Address
                exp  string
@@ -491,11 +499,40 @@ func TestAddressFormatting(t *testing.T) {
                        &Address{Name: "Rob", Address: "@"},
                        `"Rob" <@>`,
                },
+               {
+                       &Address{Name: "Böb, Jacöb", Address: "bob@example.com"},
+                       `=?utf-8?b?QsO2YiwgSmFjw7Zi?= <bob@example.com>`,
+               },
+               {
+                       &Address{Name: "=??Q?x?=", Address: "hello@world.com"},
+                       `"=??Q?x?=" <hello@world.com>`,
+               },
+               {
+                       &Address{Name: "=?hello", Address: "hello@world.com"},
+                       `"=?hello" <hello@world.com>`,
+               },
+               {
+                       &Address{Name: "world?=", Address: "hello@world.com"},
+                       `"world?=" <hello@world.com>`,
+               },
        }
        for _, test := range tests {
                s := test.addr.String()
                if s != test.exp {
                        t.Errorf("Address%+v.String() = %v, want %v", *test.addr, s, test.exp)
+                       continue
+               }
+
+               // Check round-trip.
+               if test.addr.Address != "" && test.addr.Address != "@" {
+                       a, err := ParseAddress(test.exp)
+                       if err != nil {
+                               t.Errorf("ParseAddress(%#q): %v", test.exp, err)
+                               continue
+                       }
+                       if a.Name != test.addr.Name || a.Address != test.addr.Address {
+                               t.Errorf("ParseAddress(%#q) = %#v, want %#v", test.exp, a, test.addr)
+                       }
                }
        }
 }
@@ -586,3 +623,32 @@ func TestAddressParsingAndFormatting(t *testing.T) {
        }
 
 }
+
+func TestAddressFormattingAndParsing(t *testing.T) {
+       tests := []*Address{
+               {Name: "@lïce", Address: "alice@example.com"},
+               {Name: "Böb O'Connor", Address: "bob@example.com"},
+               {Name: "???", Address: "bob@example.com"},
+               {Name: "Böb ???", Address: "bob@example.com"},
+               {Name: "Böb (Jacöb)", Address: "bob@example.com"},
+               {Name: "à#$%&'(),.:;<>@[]^`{|}~'", Address: "bob@example.com"},
+               // https://golang.org/issue/11292
+               {Name: "\"\\\x1f,\"", Address: "0@0"},
+               // https://golang.org/issue/12782
+               {Name: "naé, mée", Address: "test.mail@gmail.com"},
+       }
+
+       for i, test := range tests {
+               parsed, err := ParseAddress(test.String())
+               if err != nil {
+                       t.Errorf("test #%d: ParseAddr(%q) error: %v", i, test.String(), err)
+                       continue
+               }
+               if parsed.Name != test.Name {
+                       t.Errorf("test #%d: Parsed name = %q; want %q", i, parsed.Name, test.Name)
+               }
+               if parsed.Address != test.Address {
+                       t.Errorf("test #%d: Parsed address = %q; want %q", i, parsed.Address, test.Address)
+               }
+       }
+}
index 6e84c3a100e5af76563f50e2d114c423550a52ba..d9d23fae8f6c3a77de201b48bea91b1591c8e058 100644 (file)
@@ -345,7 +345,7 @@ var listenerBacklog = maxListenerBacklog()
 // Multiple goroutines may invoke methods on a Listener simultaneously.
 type Listener interface {
        // Accept waits for and returns the next connection to the listener.
-       Accept() (c Conn, err error)
+       Accept() (Conn, error)
 
        // Close closes the listener.
        // Any blocked Accept operations will be unblocked and return errors.
@@ -426,7 +426,16 @@ func (e *OpError) Error() string {
        return s
 }
 
-var noDeadline = time.Time{}
+var (
+       // aLongTimeAgo is a non-zero time, far in the past, used for
+       // immediate cancelation of dials.
+       aLongTimeAgo = time.Unix(233431200, 0)
+
+       // nonDeadline and noCancel are just zero values for
+       // readability with functions taking too many parameters.
+       noDeadline = time.Time{}
+       noCancel   = (chan struct{})(nil)
+)
 
 type timeout interface {
        Timeout() bool
@@ -520,10 +529,11 @@ var (
 
 // DNSError represents a DNS lookup error.
 type DNSError struct {
-       Err       string // description of the error
-       Name      string // name looked for
-       Server    string // server used
-       IsTimeout bool   // if true, timed out; not all timeouts set this
+       Err         string // description of the error
+       Name        string // name looked for
+       Server      string // server used
+       IsTimeout   bool   // if true, timed out; not all timeouts set this
+       IsTemporary bool   // if true, error is temporary; not all errors set this
 }
 
 func (e *DNSError) Error() string {
@@ -546,7 +556,7 @@ func (e *DNSError) Timeout() bool { return e.IsTimeout }
 // Temporary reports whether the DNS error is known to be temporary.
 // This is not always known; a DNS lookup may fail due to a temporary
 // error and return a DNSError for which Temporary returns false.
-func (e *DNSError) Temporary() bool { return e.IsTimeout }
+func (e *DNSError) Temporary() bool { return e.IsTimeout || e.IsTemporary }
 
 type writerOnly struct {
        io.Writer
index 3907ce4aa5664096a8844d141e380d0fdb7b81c1..6dcfc2190e03c5675a75d5952f7a5fcefbe9fbcf 100644 (file)
@@ -208,7 +208,6 @@ func TestListenerClose(t *testing.T) {
                case "unix", "unixpacket":
                        defer os.Remove(ln.Addr().String())
                }
-               defer ln.Close()
 
                if err := ln.Close(); err != nil {
                        if perr := parseCloseError(err); perr != nil {
@@ -221,6 +220,14 @@ func TestListenerClose(t *testing.T) {
                        c.Close()
                        t.Fatal("should fail")
                }
+
+               if network == "tcp" {
+                       cc, err := Dial("tcp", ln.Addr().String())
+                       if err == nil {
+                               t.Error("Dial to closed TCP listener succeeeded.")
+                               cc.Close()
+                       }
+               }
        }
 }
 
@@ -254,3 +261,26 @@ func TestPacketConnClose(t *testing.T) {
                }
        }
 }
+
+// nacl was previous failing to reuse an address.
+func TestListenCloseListen(t *testing.T) {
+       const maxTries = 10
+       for tries := 0; tries < maxTries; tries++ {
+               ln, err := newLocalListener("tcp")
+               if err != nil {
+                       t.Fatal(err)
+               }
+               addr := ln.Addr().String()
+               if err := ln.Close(); err != nil {
+                       t.Fatal(err)
+               }
+               ln, err = Listen("tcp", addr)
+               if err == nil {
+                       // Success. nacl couldn't do this before.
+                       ln.Close()
+                       return
+               }
+               t.Errorf("failed on try %d/%d: %v", tries+1, maxTries, err)
+       }
+       t.Fatalf("failed to listen/close/listen on same address after %d tries", maxTries)
+}
index eddca562f9833939f7ec330d3f642f5db65027dd..db3427e7cb4f6fc9fc4de50cc6932f137caf5828 100644 (file)
@@ -6,6 +6,17 @@
 
 package net
 
+import "runtime"
+
+// See unix_test.go for what these (don't) do.
+func forceGoDNS() func() {
+       switch runtime.GOOS {
+       case "plan9", "windows":
+               return func() {}
+       default:
+               return nil
+       }
+}
+
 // See unix_test.go for what these (don't) do.
-func forceGoDNS() func() { return func() {} }
-func forceCgoDNS() bool  { return false }
+func forceCgoDNS() func() { return nil }
index c72e1c2eaf0150e3ec8cced64bc698d091ae25d1..80836a108c98de6b007201084a9cf90ff225d93b 100644 (file)
@@ -10,6 +10,8 @@ package net
 import (
        "io"
        "os"
+       "time"
+       _ "unsafe" // For go:linkname
 )
 
 type file struct {
@@ -70,15 +72,21 @@ func open(name string) (*file, error) {
        return &file{fd, make([]byte, 0, os.Getpagesize()), false}, nil
 }
 
-func byteIndex(s string, c byte) int {
-       for i := 0; i < len(s); i++ {
-               if s[i] == c {
-                       return i
-               }
+func stat(name string) (mtime time.Time, size int64, err error) {
+       st, err := os.Stat(name)
+       if err != nil {
+               return time.Time{}, 0, err
        }
-       return -1
+       return st.ModTime(), st.Size(), nil
 }
 
+// byteIndex is strings.IndexByte. It returns the index of the
+// first instance of c in s, or -1 if c is not present in s.
+// strings.IndexByte is implemented in  runtime/asm_$GOARCH.s
+//go:linkname byteIndex strings.IndexByte
+//extern strings.IndexByte
+func byteIndex(s string, c byte) int
+
 // Count occurrences in s of any bytes in t.
 func countAnyByte(s string, t string) int {
        n := 0
@@ -120,15 +128,27 @@ const big = 0xFFFFFF
 // Returns number, new offset, success.
 func dtoi(s string, i0 int) (n int, i int, ok bool) {
        n = 0
+       neg := false
+       if len(s) > 0 && s[0] == '-' {
+               neg = true
+               s = s[1:]
+       }
        for i = i0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
                n = n*10 + int(s[i]-'0')
                if n >= big {
-                       return 0, i, false
+                       if neg {
+                               return -big, i + 1, false
+                       }
+                       return big, i, false
                }
        }
        if i == i0 {
                return 0, i, false
        }
+       if neg {
+               n = -n
+               i++
+       }
        return n, i, true
 }
 
@@ -314,14 +334,10 @@ func foreachField(x []byte, fn func(field []byte) error) error {
 
 // bytesIndexByte is bytes.IndexByte. It returns the index of the
 // first instance of c in s, or -1 if c is not present in s.
-func bytesIndexByte(s []byte, c byte) int {
-       for i, b := range s {
-               if b == c {
-                       return i
-               }
-       }
-       return -1
-}
+// bytes.IndexByte is implemented in  runtime/asm_$GOARCH.s
+//go:linkname bytesIndexByte bytes.IndexByte
+//extern bytes.IndexByte
+func bytesIndexByte(s []byte, c byte) int
 
 // stringsHasSuffix is strings.HasSuffix. It reports whether s ends in
 // suffix.
index 0f048fcea0bbb0cb78eeb30f926565a01cc54abf..fec92009465516712c0a6302775a6579195d446c 100644 (file)
@@ -77,3 +77,25 @@ func TestGoDebugString(t *testing.T) {
                }
        }
 }
+
+func TestDtoi(t *testing.T) {
+       for _, tt := range []struct {
+               in  string
+               out int
+               off int
+               ok  bool
+       }{
+               {"", 0, 0, false},
+
+               {"-123456789", -big, 9, false},
+               {"-1", -1, 2, true},
+               {"0", 0, 1, true},
+               {"65536", 65536, 5, true},
+               {"123456789", big, 8, false},
+       } {
+               n, i, ok := dtoi(tt.in, 0)
+               if n != tt.out || i != tt.off || ok != tt.ok {
+                       t.Errorf("got %d, %d, %v; want %d, %d, %v", n, i, ok, tt.out, tt.off, tt.ok)
+               }
+       }
+}
index d6248520f33b6910e0d11603c9d67e3a2b248b0a..76c53138cdd7aace299f399f87e1c82377a04e5f 100644 (file)
@@ -32,7 +32,7 @@ func testableNetwork(network string) bool {
                }
        case "unix", "unixgram":
                switch runtime.GOOS {
-               case "nacl", "plan9", "windows":
+               case "android", "nacl", "plan9", "windows":
                        return false
                }
                // iOS does not support unix, unixgram.
@@ -134,7 +134,7 @@ func testableListenArgs(network, address, client string) bool {
 
        // Test functionality of IPv4 communication using AF_INET6
        // sockets.
-       if !supportsIPv4map && (network == "tcp" || network == "udp" || network == "ip") && wildcard {
+       if !supportsIPv4map && supportsIPv4 && (network == "tcp" || network == "udp" || network == "ip") && wildcard {
                // At this point, we prefer IPv4 when ip is nil.
                // See favoriteAddrFamily for further information.
                if ip.To16() != nil && ip.To4() == nil && cip.To4() != nil { // a pair of IPv6 server and IPv4 client
diff --git a/libgo/go/net/port.go b/libgo/go/net/port.go
deleted file mode 100644 (file)
index a2a5387..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2012 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.
-
-// Network service port manipulations
-
-package net
-
-// parsePort parses port as a network service port number for both
-// TCP and UDP.
-func parsePort(net, port string) (int, error) {
-       p, i, ok := dtoi(port, 0)
-       if !ok || i != len(port) {
-               var err error
-               p, err = LookupPort(net, port)
-               if err != nil {
-                       return 0, err
-               }
-       }
-       if p < 0 || p > 0xFFFF {
-               return 0, &AddrError{Err: "invalid port", Addr: port}
-       }
-       return p, nil
-}
diff --git a/libgo/go/net/port_test.go b/libgo/go/net/port_test.go
deleted file mode 100644 (file)
index 258a5bd..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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 (
-       "runtime"
-       "testing"
-)
-
-var portTests = []struct {
-       network string
-       name    string
-       port    int
-       ok      bool
-}{
-       {"tcp", "echo", 7, true},
-       {"tcp", "discard", 9, true},
-       {"tcp", "systat", 11, true},
-       {"tcp", "daytime", 13, true},
-       {"tcp", "chargen", 19, true},
-       {"tcp", "ftp-data", 20, true},
-       {"tcp", "ftp", 21, true},
-       {"tcp", "telnet", 23, true},
-       {"tcp", "smtp", 25, true},
-       {"tcp", "time", 37, true},
-       {"tcp", "domain", 53, true},
-       {"tcp", "finger", 79, true},
-       {"tcp", "42", 42, true},
-
-       {"udp", "echo", 7, true},
-       {"udp", "tftp", 69, true},
-       {"udp", "bootpc", 68, true},
-       {"udp", "bootps", 67, true},
-       {"udp", "domain", 53, true},
-       {"udp", "ntp", 123, true},
-       {"udp", "snmp", 161, true},
-       {"udp", "syslog", 514, true},
-       {"udp", "42", 42, true},
-
-       {"--badnet--", "zzz", 0, false},
-       {"tcp", "--badport--", 0, false},
-}
-
-func TestLookupPort(t *testing.T) {
-       switch runtime.GOOS {
-       case "nacl":
-               t.Skipf("not supported on %s", runtime.GOOS)
-       }
-
-       for _, tt := range portTests {
-               if port, err := LookupPort(tt.network, tt.name); port != tt.port || (err == nil) != tt.ok {
-                       t.Errorf("LookupPort(%q, %q) = %v, %v; want %v", tt.network, tt.name, port, err, tt.port)
-               }
-       }
-}
diff --git a/libgo/go/net/race.go b/libgo/go/net/race.go
deleted file mode 100644 (file)
index 2f02a6c..0000000
+++ /dev/null
@@ -1,31 +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 race
-// +build windows
-
-package net
-
-import (
-       "runtime"
-       "unsafe"
-)
-
-const raceenabled = true
-
-func raceAcquire(addr unsafe.Pointer) {
-       runtime.RaceAcquire(addr)
-}
-
-func raceReleaseMerge(addr unsafe.Pointer) {
-       runtime.RaceReleaseMerge(addr)
-}
-
-func raceReadRange(addr unsafe.Pointer, len int) {
-       runtime.RaceReadRange(addr, len)
-}
-
-func raceWriteRange(addr unsafe.Pointer, len int) {
-       runtime.RaceWriteRange(addr, len)
-}
diff --git a/libgo/go/net/race0.go b/libgo/go/net/race0.go
deleted file mode 100644 (file)
index f504297..0000000
+++ /dev/null
@@ -1,26 +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 !race
-// +build windows
-
-package net
-
-import (
-       "unsafe"
-)
-
-const raceenabled = false
-
-func raceAcquire(addr unsafe.Pointer) {
-}
-
-func raceReleaseMerge(addr unsafe.Pointer) {
-}
-
-func raceReadRange(addr unsafe.Pointer, len int) {
-}
-
-func raceWriteRange(addr unsafe.Pointer, len int) {
-}
index 6e6e881917494effee20b2deae4d1057523bac97..c4d4479958adc781e3dbc0c600130156c784d01d 100644 (file)
@@ -611,13 +611,15 @@ func (server *Server) readRequestHeader(codec ServerCodec) (service *service, mt
 }
 
 // Accept accepts connections on the listener and serves requests
-// for each incoming connection.  Accept blocks; the caller typically
-// invokes it in a go statement.
+// for each incoming connection. Accept blocks until the listener
+// returns a non-nil error. The caller typically invokes Accept in a
+// go statement.
 func (server *Server) Accept(lis net.Listener) {
        for {
                conn, err := lis.Accept()
                if err != nil {
-                       log.Fatal("rpc.Serve: accept:", err.Error()) // TODO(r): exit?
+                       log.Print("rpc.Serve: accept:", err.Error())
+                       return
                }
                go server.ServeConn(conn)
        }
index 0dc4ddc2de01cb0e130b0f569e13f16e1c21646f..8871c88133c845f1da874dd4e0444aad8975c4f2 100644 (file)
@@ -74,6 +74,17 @@ func (t *Arith) Error(args *Args, reply *Reply) error {
        panic("ERROR")
 }
 
+type hidden int
+
+func (t *hidden) Exported(args Args, reply *Reply) error {
+       reply.C = args.A + args.B
+       return nil
+}
+
+type Embed struct {
+       hidden
+}
+
 func listenTCP() (net.Listener, string) {
        l, e := net.Listen("tcp", "127.0.0.1:0") // any available address
        if e != nil {
@@ -84,6 +95,7 @@ func listenTCP() (net.Listener, string) {
 
 func startServer() {
        Register(new(Arith))
+       Register(new(Embed))
        RegisterName("net.rpc.Arith", new(Arith))
 
        var l net.Listener
@@ -98,6 +110,7 @@ func startServer() {
 func startNewServer() {
        newServer = NewServer()
        newServer.Register(new(Arith))
+       newServer.Register(new(Embed))
        newServer.RegisterName("net.rpc.Arith", new(Arith))
        newServer.RegisterName("newServer.Arith", new(Arith))
 
@@ -142,6 +155,17 @@ func testRPC(t *testing.T, addr string) {
                t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
        }
 
+       // Methods exported from unexported embedded structs
+       args = &Args{7, 0}
+       reply = new(Reply)
+       err = client.Call("Embed.Exported", args, reply)
+       if err != nil {
+               t.Errorf("Add: expected no error but got string %q", err.Error())
+       }
+       if reply.C != args.A+args.B {
+               t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
+       }
+
        // Nonexistent method
        args = &Args{7, 0}
        reply = new(Reply)
@@ -593,6 +617,19 @@ func TestErrorAfterClientClose(t *testing.T) {
        }
 }
 
+// Tests the fix to issue 11221. Without the fix, this loops forever or crashes.
+func TestAcceptExitAfterListenerClose(t *testing.T) {
+       newServer = NewServer()
+       newServer.Register(new(Arith))
+       newServer.RegisterName("net.rpc.Arith", new(Arith))
+       newServer.RegisterName("newServer.Arith", new(Arith))
+
+       var l net.Listener
+       l, newServerAddr = listenTCP()
+       l.Close()
+       newServer.Accept(l)
+}
+
 func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) {
        once.Do(startServer)
        client, err := dial()
index 0966575696be2e3b82304db1d54c94b17a50287d..f6833813fd0a0f79d9d520a440cf91a7882c7d45 100644 (file)
@@ -26,6 +26,8 @@ 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) {
+       return // Solaris sendfile is disabled until Issue 13892 is understood and fixed
+
        // Solaris 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 nauseam until it's sent
        // exactly the number of bytes told to. As such, we need to know exactly how many
index fe0006b11fb0370b8de9ee10288e7ebb55118aca..2e998e23a8a0aba1bb3f3687d7fc0d9bfa6235db 100644 (file)
@@ -55,7 +55,7 @@ func TestTCPServer(t *testing.T) {
 
        for i, tt := range tcpServerTests {
                if !testableListenArgs(tt.snet, tt.saddr, tt.taddr) {
-                       t.Logf("skipping %s test", tt.snet+" "+tt.saddr+"->"+tt.taddr)
+                       t.Logf("skipping %s test", tt.snet+" "+tt.saddr+"<-"+tt.taddr)
                        continue
                }
 
@@ -251,7 +251,7 @@ var udpServerTests = []struct {
 func TestUDPServer(t *testing.T) {
        for i, tt := range udpServerTests {
                if !testableListenArgs(tt.snet, tt.saddr, tt.taddr) {
-                       t.Logf("skipping %s test", tt.snet+" "+tt.saddr+"->"+tt.taddr)
+                       t.Logf("skipping %s test", tt.snet+" "+tt.saddr+"<-"+tt.taddr)
                        continue
                }
 
@@ -329,7 +329,7 @@ var unixgramServerTests = []struct {
 func TestUnixgramServer(t *testing.T) {
        for i, tt := range unixgramServerTests {
                if !testableListenArgs("unixgram", tt.saddr, "") {
-                       t.Logf("skipping %s test", "unixgram "+tt.saddr+"->"+tt.caddr)
+                       t.Logf("skipping %s test", "unixgram "+tt.saddr+"<-"+tt.caddr)
                        continue
                }
 
index 4d2cfde3f1c8832bd7a30817f3e1bd4f4010f53c..46767215672c9c862c47af8ce44c0066f174275a 100644 (file)
@@ -34,7 +34,7 @@ type sockaddr interface {
 
 // socket returns a network file descriptor that is ready for
 // asynchronous I/O using the network poller.
-func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr, deadline time.Time) (fd *netFD, err error) {
+func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr, deadline time.Time, cancel <-chan struct{}) (fd *netFD, err error) {
        s, err := sysSocket(family, sotype, proto)
        if err != nil {
                return nil, err
@@ -86,7 +86,7 @@ func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr s
                        return fd, nil
                }
        }
-       if err := fd.dial(laddr, raddr, deadline); err != nil {
+       if err := fd.dial(laddr, raddr, deadline, cancel); err != nil {
                fd.Close()
                return nil, err
        }
@@ -117,7 +117,7 @@ func (fd *netFD) addrFunc() func(syscall.Sockaddr) Addr {
        return func(syscall.Sockaddr) Addr { return nil }
 }
 
-func (fd *netFD) dial(laddr, raddr sockaddr, deadline time.Time) error {
+func (fd *netFD) dial(laddr, raddr sockaddr, deadline time.Time, cancel <-chan struct{}) error {
        var err error
        var lsa syscall.Sockaddr
        if laddr != nil {
@@ -134,7 +134,7 @@ func (fd *netFD) dial(laddr, raddr sockaddr, deadline time.Time) error {
                if rsa, err = raddr.sockaddr(fd.family); err != nil {
                        return err
                }
-               if err := fd.connect(lsa, rsa, deadline); err != nil {
+               if err := fd.connect(lsa, rsa, deadline, cancel); err != nil {
                        return err
                }
                fd.isConnected = true
index 25ae9b9d771ca4b1661899ddd59136f78003d45b..9da6f6cdd05b52fa175b4e77d65701f1f035a376 100644 (file)
@@ -540,9 +540,12 @@ func TestTCPStress(t *testing.T) {
        if err != nil {
                t.Fatal(err)
        }
-       defer ln.Close()
+       done := make(chan bool)
        // Acceptor.
        go func() {
+               defer func() {
+                       done <- true
+               }()
                for {
                        c, err := ln.Accept()
                        if err != nil {
@@ -560,7 +563,6 @@ func TestTCPStress(t *testing.T) {
                        }(c)
                }
        }()
-       done := make(chan bool)
        for i := 0; i < conns; i++ {
                // Client connection.
                go func() {
@@ -584,4 +586,6 @@ func TestTCPStress(t *testing.T) {
        for i := 0; i < conns; i++ {
                <-done
        }
+       ln.Close()
+       <-done
 }
index 9f23703abb4325ce4705fdd1c86c8c9dc460fb0e..afccbfe8a749bc85ec864b382529d8d0a95a65db 100644 (file)
@@ -107,13 +107,14 @@ func (c *TCPConn) SetNoDelay(noDelay bool) error {
 // which must be "tcp", "tcp4", or "tcp6".  If laddr is not nil, it is
 // used as the local address for the connection.
 func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
-       return dialTCP(net, laddr, raddr, noDeadline)
+       return dialTCP(net, laddr, raddr, noDeadline, noCancel)
 }
 
-func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, error) {
+func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time, cancel <-chan struct{}) (*TCPConn, error) {
        if !deadline.IsZero() {
                panic("net.dialTCP: deadline not implemented on Plan 9")
        }
+       // TODO(bradfitz,0intro): also use the cancel channel.
        switch net {
        case "tcp", "tcp4", "tcp6":
        default:
index 7e49b769e1c98c841e3bfc4798db639d6b5bb9cf..0e12d54300265d18ca7404928c22bac2d8bcbd43 100644 (file)
@@ -164,11 +164,11 @@ func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
        if raddr == nil {
                return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
        }
-       return dialTCP(net, laddr, raddr, noDeadline)
+       return dialTCP(net, laddr, raddr, noDeadline, noCancel)
 }
 
-func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, error) {
-       fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_STREAM, 0, "dial")
+func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time, cancel <-chan struct{}) (*TCPConn, error) {
+       fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_STREAM, 0, "dial", cancel)
 
        // TCP has a rarely used mechanism called a 'simultaneous connection' in
        // which Dial("tcp", addr1, addr2) run on the machine at addr1 can
@@ -198,7 +198,7 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e
                if err == nil {
                        fd.Close()
                }
-               fd, err = internetSocket(net, laddr, raddr, deadline, syscall.SOCK_STREAM, 0, "dial")
+               fd, err = internetSocket(net, laddr, raddr, deadline, syscall.SOCK_STREAM, 0, "dial", cancel)
        }
 
        if err != nil {
@@ -326,7 +326,7 @@ func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
        if laddr == nil {
                laddr = &TCPAddr{}
        }
-       fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_STREAM, 0, "listen")
+       fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_STREAM, 0, "listen", noCancel)
        if err != nil {
                return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
        }
index 9abe186cecb4ea4160d196b86c282c95df605a73..157282abd34b7ec0e4746f3b2c1a570a43689bf3 100644 (file)
@@ -7,13 +7,12 @@
 package net
 
 import (
-       "strconv"
        "time"
 )
 
 // Set keep alive period.
 func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
-       cmd := "keepalive " + strconv.Itoa(int(d/time.Millisecond))
+       cmd := "keepalive " + itoa(int(d/time.Millisecond))
        _, e := fd.ctl.WriteAt([]byte(cmd), 0)
        return e
 }
diff --git a/libgo/go/net/testdata/case-hosts b/libgo/go/net/testdata/case-hosts
new file mode 100644 (file)
index 0000000..1f30df1
--- /dev/null
@@ -0,0 +1,2 @@
+127.0.0.1      PreserveMe      PreserveMe.local
+::1            PreserveMe      PreserveMe.local
index b601763898b7e27ded621cc207effa4a403cecc0..3ed83ff8a83ea2e2eebbf7f03bdd0a49b4aed374 100644 (file)
@@ -5,8 +5,7 @@
 127.1.1.1      thor
 # aliases
 127.1.1.2      ullr ullrhost
+fe80::1%lo0    localhost
 # Bogus entries that must be ignored.
 123.123.123    loki
 321.321.321.321
-# TODO(yvesj): Should we be able to parse this? From a Darwin system.
-fe80::1%lo0    localhost
index 91303fec612dfcfc8e21edf9e653ec638ea180ff..91bbb573043c77e262e0de5908a22bd363b969fd 100644 (file)
@@ -150,7 +150,7 @@ func (r *Reader) readContinuedLineSlice() ([]byte, error) {
                        break
                }
                r.buf = append(r.buf, ' ')
-               r.buf = append(r.buf, line...)
+               r.buf = append(r.buf, trim(line)...)
        }
        return r.buf, nil
 }
@@ -237,7 +237,12 @@ func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err err
 // separated by a newline (\n).
 //
 // See page 36 of RFC 959 (http://www.ietf.org/rfc/rfc959.txt) for
-// details.
+// details of another form of response accepted:
+//
+//  code-message line 1
+//  message line 2
+//  ...
+//  code message line n
 //
 // If the prefix of the status does not match the digits in expectCode,
 // ReadResponse returns with err set to &Error{code, message}.
@@ -248,7 +253,8 @@ func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err err
 //
 func (r *Reader) ReadResponse(expectCode int) (code int, message string, err error) {
        code, continued, message, err := r.readCodeLine(expectCode)
-       for err == nil && continued {
+       multi := continued
+       for continued {
                line, err := r.ReadLine()
                if err != nil {
                        return 0, "", err
@@ -256,7 +262,7 @@ func (r *Reader) ReadResponse(expectCode int) (code int, message string, err err
 
                var code2 int
                var moreMessage string
-               code2, continued, moreMessage, err = parseCodeLine(line, expectCode)
+               code2, continued, moreMessage, err = parseCodeLine(line, 0)
                if err != nil || code2 != code {
                        message += "\n" + strings.TrimRight(line, "\r\n")
                        continued = true
@@ -264,6 +270,10 @@ func (r *Reader) ReadResponse(expectCode int) (code int, message string, err err
                }
                message += "\n" + moreMessage
        }
+       if err != nil && multi && message != "" {
+               // replace one line error message with all lines (full message)
+               err = &Error{code, message}
+       }
        return
 }
 
index 91550f749346046785b032662b881a6a87f3c589..93d7939bb5f4c7cf710dfb6c8701e371f4d75774 100644 (file)
@@ -205,6 +205,32 @@ func TestReadMIMEHeaderNonCompliant(t *testing.T) {
        }
 }
 
+// Test that continued lines are properly trimmed. Issue 11204.
+func TestReadMIMEHeaderTrimContinued(t *testing.T) {
+       // In this header, \n and \r\n terminated lines are mixed on purpose.
+       // We expect each line to be trimmed (prefix and suffix) before being concatenated.
+       // Keep the spaces as they are.
+       r := reader("" + // for code formatting purpose.
+               "a:\n" +
+               " 0 \r\n" +
+               "b:1 \t\r\n" +
+               "c: 2\r\n" +
+               " 3\t\n" +
+               "  \t 4  \r\n\n")
+       m, err := r.ReadMIMEHeader()
+       if err != nil {
+               t.Fatal(err)
+       }
+       want := MIMEHeader{
+               "A": {"0"},
+               "B": {"1"},
+               "C": {"2 3 4"},
+       }
+       if !reflect.DeepEqual(m, want) {
+               t.Fatalf("ReadMIMEHeader mismatch.\n got: %q\nwant: %q", m, want)
+       }
+}
+
 type readResponseTest struct {
        in       string
        inCode   int
@@ -258,6 +284,35 @@ func TestRFC959Lines(t *testing.T) {
        }
 }
 
+// Test that multi-line errors are appropriately and fully read. Issue 10230.
+func TestReadMultiLineError(t *testing.T) {
+       r := reader("550-5.1.1 The email account that you tried to reach does not exist. Please try\n" +
+               "550-5.1.1 double-checking the recipient's email address for typos or\n" +
+               "550-5.1.1 unnecessary spaces. Learn more at\n" +
+               "Unexpected but legal text!\n" +
+               "550 5.1.1 https://support.google.com/mail/answer/6596 h20si25154304pfd.166 - gsmtp\n")
+
+       wantMsg := "5.1.1 The email account that you tried to reach does not exist. Please try\n" +
+               "5.1.1 double-checking the recipient's email address for typos or\n" +
+               "5.1.1 unnecessary spaces. Learn more at\n" +
+               "Unexpected but legal text!\n" +
+               "5.1.1 https://support.google.com/mail/answer/6596 h20si25154304pfd.166 - gsmtp"
+
+       code, msg, err := r.ReadResponse(250)
+       if err == nil {
+               t.Errorf("ReadResponse: no error, want error")
+       }
+       if code != 550 {
+               t.Errorf("ReadResponse: code=%d, want %d", code, 550)
+       }
+       if msg != wantMsg {
+               t.Errorf("ReadResponse: msg=%q, want %q", msg, wantMsg)
+       }
+       if err.Error() != "550 "+wantMsg {
+               t.Errorf("ReadResponse: error=%q, want %q", err.Error(), "550 "+wantMsg)
+       }
+}
+
 func TestCommonHeaders(t *testing.T) {
        for h := range commonHeader {
                if h != CanonicalMIMEHeaderKey(h) {
index ca94e24c81685cfc3e67655a544efea12a0a1e01..98e3164fb9897a12fc022be72cc2c955bdb770c2 100644 (file)
@@ -33,6 +33,7 @@ var dialTimeoutTests = []struct {
 }
 
 func TestDialTimeout(t *testing.T) {
+       // Cannot use t.Parallel - modifies global hooks.
        origTestHookDialChannel := testHookDialChannel
        defer func() { testHookDialChannel = origTestHookDialChannel }()
        defer sw.Set(socktest.FilterConnect, nil)
@@ -110,6 +111,8 @@ var acceptTimeoutTests = []struct {
 }
 
 func TestAcceptTimeout(t *testing.T) {
+       t.Parallel()
+
        switch runtime.GOOS {
        case "plan9":
                t.Skipf("not supported on %s", runtime.GOOS)
@@ -161,6 +164,8 @@ func TestAcceptTimeout(t *testing.T) {
 }
 
 func TestAcceptTimeoutMustReturn(t *testing.T) {
+       t.Parallel()
+
        switch runtime.GOOS {
        case "plan9":
                t.Skipf("not supported on %s", runtime.GOOS)
@@ -205,6 +210,8 @@ func TestAcceptTimeoutMustReturn(t *testing.T) {
 }
 
 func TestAcceptTimeoutMustNotReturn(t *testing.T) {
+       t.Parallel()
+
        switch runtime.GOOS {
        case "plan9":
                t.Skipf("not supported on %s", runtime.GOOS)
@@ -254,6 +261,8 @@ var readTimeoutTests = []struct {
 }
 
 func TestReadTimeout(t *testing.T) {
+       t.Parallel()
+
        switch runtime.GOOS {
        case "plan9":
                t.Skipf("not supported on %s", runtime.GOOS)
@@ -313,6 +322,8 @@ func TestReadTimeout(t *testing.T) {
 }
 
 func TestReadTimeoutMustNotReturn(t *testing.T) {
+       t.Parallel()
+
        switch runtime.GOOS {
        case "plan9":
                t.Skipf("not supported on %s", runtime.GOOS)
@@ -454,6 +465,8 @@ var writeTimeoutTests = []struct {
 }
 
 func TestWriteTimeout(t *testing.T) {
+       t.Parallel()
+
        switch runtime.GOOS {
        case "plan9":
                t.Skipf("not supported on %s", runtime.GOOS)
@@ -500,6 +513,8 @@ func TestWriteTimeout(t *testing.T) {
 }
 
 func TestWriteTimeoutMustNotReturn(t *testing.T) {
+       t.Parallel()
+
        switch runtime.GOOS {
        case "plan9":
                t.Skipf("not supported on %s", runtime.GOOS)
@@ -569,6 +584,8 @@ var writeToTimeoutTests = []struct {
 }
 
 func TestWriteToTimeout(t *testing.T) {
+       t.Parallel()
+
        switch runtime.GOOS {
        case "nacl", "plan9":
                t.Skipf("not supported on %s", runtime.GOOS)
@@ -620,6 +637,8 @@ func TestWriteToTimeout(t *testing.T) {
 }
 
 func TestReadTimeoutFluctuation(t *testing.T) {
+       t.Parallel()
+
        switch runtime.GOOS {
        case "plan9":
                t.Skipf("not supported on %s", runtime.GOOS)
@@ -656,6 +675,8 @@ func TestReadTimeoutFluctuation(t *testing.T) {
 }
 
 func TestReadFromTimeoutFluctuation(t *testing.T) {
+       t.Parallel()
+
        switch runtime.GOOS {
        case "plan9":
                t.Skipf("not supported on %s", runtime.GOOS)
@@ -692,6 +713,8 @@ func TestReadFromTimeoutFluctuation(t *testing.T) {
 }
 
 func TestWriteTimeoutFluctuation(t *testing.T) {
+       t.Parallel()
+
        switch runtime.GOOS {
        case "plan9":
                t.Skipf("not supported on %s", runtime.GOOS)
@@ -731,12 +754,27 @@ func TestWriteTimeoutFluctuation(t *testing.T) {
        }
 }
 
+func TestVariousDeadlines(t *testing.T) {
+       t.Parallel()
+       testVariousDeadlines(t)
+}
+
 func TestVariousDeadlines1Proc(t *testing.T) {
-       testVariousDeadlines(t, 1)
+       // Cannot use t.Parallel - modifies global GOMAXPROCS.
+       if testing.Short() {
+               t.Skip("skipping in short mode")
+       }
+       defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+       testVariousDeadlines(t)
 }
 
 func TestVariousDeadlines4Proc(t *testing.T) {
-       testVariousDeadlines(t, 4)
+       // Cannot use t.Parallel - modifies global GOMAXPROCS.
+       if testing.Short() {
+               t.Skip("skipping in short mode")
+       }
+       defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+       testVariousDeadlines(t)
 }
 
 type neverEnding byte
@@ -748,14 +786,12 @@ func (b neverEnding) Read(p []byte) (int, error) {
        return len(p), nil
 }
 
-func testVariousDeadlines(t *testing.T, maxProcs int) {
+func testVariousDeadlines(t *testing.T) {
        switch runtime.GOOS {
        case "plan9":
                t.Skipf("not supported on %s", runtime.GOOS)
        }
 
-       defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
-
        type result struct {
                n   int64
                err error
@@ -869,6 +905,8 @@ func testVariousDeadlines(t *testing.T, maxProcs int) {
 // TestReadWriteProlongedTimeout tests concurrent deadline
 // modification. Known to cause data races in the past.
 func TestReadWriteProlongedTimeout(t *testing.T) {
+       t.Parallel()
+
        switch runtime.GOOS {
        case "plan9":
                t.Skipf("not supported on %s", runtime.GOOS)
@@ -947,6 +985,8 @@ func TestReadWriteProlongedTimeout(t *testing.T) {
 }
 
 func TestReadWriteDeadlineRace(t *testing.T) {
+       t.Parallel()
+
        switch runtime.GOOS {
        case "nacl", "plan9":
                t.Skipf("not supported on %s", runtime.GOOS)
@@ -956,7 +996,6 @@ func TestReadWriteDeadlineRace(t *testing.T) {
        if testing.Short() {
                N = 50
        }
-       defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
 
        ln, err := newLocalListener("tcp")
        if err != nil {
index 61868c4b0cfc2a39c1daa75ad7b1fcb9cb9370df..932c6ce713fe462790840752457281addba71327 100644 (file)
@@ -189,7 +189,7 @@ func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
 }
 
 func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) {
-       fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_DGRAM, 0, "dial")
+       fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_DGRAM, 0, "dial", noCancel)
        if err != nil {
                return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
        }
@@ -212,7 +212,7 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
        if laddr == nil {
                laddr = &UDPAddr{}
        }
-       fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen")
+       fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", noCancel)
        if err != nil {
                return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
        }
@@ -239,7 +239,7 @@ func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPCon
        if gaddr == nil || gaddr.IP == nil {
                return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: errMissingAddress}
        }
-       fd, err := internetSocket(network, gaddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen")
+       fd, err := internetSocket(network, gaddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", noCancel)
        if err != nil {
                return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr, Err: err}
        }
index 358ff310725de29b2dc26254546bab01059fde9c..f0c583068ec08abf6bb93965e37107b3978ae02b 100644 (file)
@@ -405,6 +405,42 @@ func TestUnixgramConnLocalAndRemoteNames(t *testing.T) {
        }
 }
 
+func TestUnixUnlink(t *testing.T) {
+       if !testableNetwork("unix") {
+               t.Skip("unix test")
+       }
+       name := testUnixAddr()
+       l, err := Listen("unix", name)
+       if err != nil {
+               t.Fatal(err)
+       }
+       if _, err := os.Stat(name); err != nil {
+               t.Fatalf("cannot stat unix socket after ListenUnix: %v", err)
+       }
+       f, _ := l.(*UnixListener).File()
+       l1, err := FileListener(f)
+       if err != nil {
+               t.Fatal(err)
+       }
+       if _, err := os.Stat(name); err != nil {
+               t.Fatalf("cannot stat unix socket after FileListener: %v", err)
+       }
+       if err := l1.Close(); err != nil {
+               t.Fatalf("closing file listener: %v", err)
+       }
+       if _, err := os.Stat(name); err != nil {
+               t.Fatalf("cannot stat unix socket after closing FileListener: %v", err)
+       }
+       f.Close()
+       if _, err := os.Stat(name); err != nil {
+               t.Fatalf("cannot stat unix socket after closing FileListener and fd: %v", err)
+       }
+       l.Close()
+       if _, err := os.Stat(name); err == nil {
+               t.Fatal("closing unix listener did not remove unix socket")
+       }
+}
+
 // forceGoDNS forces the resolver configuration to use the pure Go resolver
 // and returns a fixup function to restore the old settings.
 func forceGoDNS() func() {
@@ -421,11 +457,17 @@ func forceGoDNS() func() {
 }
 
 // forceCgoDNS forces the resolver configuration to use the cgo resolver
-// and returns true to indicate that it did so.
-// (On non-Unix systems forceCgoDNS returns false.)
-func forceCgoDNS() bool {
+// and returns a fixup function to restore the old settings.
+// (On non-Unix systems forceCgoDNS returns nil.)
+func forceCgoDNS() func() {
        c := systemConf()
+       oldGo := c.netGo
+       oldCgo := c.netCgo
+       fixup := func() {
+               c.netGo = oldGo
+               c.netCgo = oldCgo
+       }
        c.netGo = false
        c.netCgo = true
-       return true
+       return fixup
 }
index 351d9b3a39ae6b6e54c4c2ff8ad95c5bc53d95c0..fb2397e26f2b5b038355689bd6ee1e859cc80040 100644 (file)
@@ -42,7 +42,7 @@ func unixSocket(net string, laddr, raddr sockaddr, mode string, deadline time.Ti
                return nil, errors.New("unknown mode: " + mode)
        }
 
-       fd, err := socket(net, syscall.AF_UNIX, sotype, 0, false, laddr, raddr, deadline)
+       fd, err := socket(net, syscall.AF_UNIX, sotype, 0, false, laddr, raddr, deadline, noCancel)
        if err != nil {
                return nil, err
        }
@@ -273,8 +273,9 @@ func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn
 // typically use variables of type Listener instead of assuming Unix
 // domain sockets.
 type UnixListener struct {
-       fd   *netFD
-       path string
+       fd     *netFD
+       path   string
+       unlink bool
 }
 
 // ListenUnix announces on the Unix domain socket laddr and returns a
@@ -292,7 +293,7 @@ func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
        if err != nil {
                return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
        }
-       return &UnixListener{fd: fd, path: fd.laddr.String()}, nil
+       return &UnixListener{fd: fd, path: fd.laddr.String(), unlink: true}, nil
 }
 
 // AcceptUnix accepts the next incoming call and returns the new
@@ -335,7 +336,7 @@ func (l *UnixListener) Close() error {
        // is at least compatible with the auto-remove
        // sequence in ListenUnix.  It's only non-Go
        // programs that can mess us up.
-       if l.path[0] != '@' {
+       if l.path[0] != '@' && l.unlink {
                syscall.Unlink(l.path)
        }
        err := l.fd.Close()
index 8ffad663d5cf062e96055131a48a5c51cab66434..1a93e3496edb00446c0c667aff6ea66258c6344f 100644 (file)
@@ -24,6 +24,24 @@ type Error struct {
 
 func (e *Error) Error() string { return e.Op + " " + e.URL + ": " + e.Err.Error() }
 
+type timeout interface {
+       Timeout() bool
+}
+
+func (e *Error) Timeout() bool {
+       t, ok := e.Err.(timeout)
+       return ok && t.Timeout()
+}
+
+type temporary interface {
+       Temporary() bool
+}
+
+func (e *Error) Temporary() bool {
+       t, ok := e.Err.(temporary)
+       return ok && t.Temporary()
+}
+
 func ishex(c byte) bool {
        switch {
        case '0' <= c && c <= '9':
@@ -53,6 +71,7 @@ type encoding int
 const (
        encodePath encoding = 1 + iota
        encodeHost
+       encodeZone
        encodeUserPassword
        encodeQueryComponent
        encodeFragment
@@ -64,6 +83,12 @@ func (e EscapeError) Error() string {
        return "invalid URL escape " + strconv.Quote(string(e))
 }
 
+type InvalidHostError string
+
+func (e InvalidHostError) Error() string {
+       return "invalid character " + strconv.Quote(string(e)) + " in host name"
+}
+
 // Return true if the specified character should be escaped when
 // appearing in a URL string, according to RFC 3986.
 //
@@ -75,14 +100,18 @@ func shouldEscape(c byte, mode encoding) bool {
                return false
        }
 
-       if mode == encodeHost {
+       if mode == encodeHost || mode == encodeZone {
                // §3.2.2 Host allows
                //      sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
                // as part of reg-name.
                // We add : because we include :port as part of host.
-               // We add [ ] because we include [ipv6]:port as part of host
+               // We add [ ] because we include [ipv6]:port as part of host.
+               // We add < > because they're the only characters left that
+               // we could possibly allow, and Parse will reject them if we
+               // escape them (because hosts can't use %-encoding for
+               // ASCII bytes).
                switch c {
-               case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '[', ']':
+               case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '[', ']', '<', '>', '"':
                        return false
                }
        }
@@ -148,11 +177,36 @@ func unescape(s string, mode encoding) (string, error) {
                                }
                                return "", EscapeError(s)
                        }
+                       // Per https://tools.ietf.org/html/rfc3986#page-21
+                       // in the host component %-encoding can only be used
+                       // for non-ASCII bytes.
+                       // But https://tools.ietf.org/html/rfc6874#section-2
+                       // introduces %25 being allowed to escape a percent sign
+                       // in IPv6 scoped-address literals. Yay.
+                       if mode == encodeHost && unhex(s[i+1]) < 8 && s[i:i+3] != "%25" {
+                               return "", EscapeError(s[i : i+3])
+                       }
+                       if mode == encodeZone {
+                               // RFC 6874 says basically "anything goes" for zone identifiers
+                               // and that even non-ASCII can be redundantly escaped,
+                               // but it seems prudent to restrict %-escaped bytes here to those
+                               // that are valid host name bytes in their unescaped form.
+                               // That is, you can use escaping in the zone identifier but not
+                               // to introduce bytes you couldn't just write directly.
+                               // But Windows puts spaces here! Yay.
+                               v := unhex(s[i+1])<<4 | unhex(s[i+2])
+                               if s[i:i+3] != "%25" && v != ' ' && shouldEscape(v, encodeHost) {
+                                       return "", EscapeError(s[i : i+3])
+                               }
+                       }
                        i += 3
                case '+':
                        hasPlus = mode == encodeQueryComponent
                        i++
                default:
+                       if (mode == encodeHost || mode == encodeZone) && s[i] < 0x80 && shouldEscape(s[i], mode) {
+                               return "", InvalidHostError(s[i : i+1])
+                       }
                        i++
                }
        }
@@ -246,7 +300,7 @@ func escape(s string, mode encoding) string {
 // Go 1.5 introduced the RawPath field to hold the encoded form of Path.
 // The Parse function sets both Path and RawPath in the URL it returns,
 // and URL's String method uses RawPath if it is a valid encoding of Path,
-// by calling the EncodedPath method.
+// by calling the EscapedPath method.
 //
 // In earlier versions of Go, the more indirect workarounds were that an
 // HTTP server could consult req.RequestURI and an HTTP client could
@@ -431,7 +485,7 @@ func parse(rawurl string, viaRequest bool) (url *URL, err error) {
                goto Error
        }
        // RawPath is a hint as to the encoding of Path to use
-       // in url.EncodedPath. If that method already gets the
+       // in url.EscapedPath. If that method already gets the
        // right answer without RawPath, leave it empty.
        // This will help make sure that people don't rely on it in general.
        if url.EscapedPath() != rest && validEncodedPath(rest) {
@@ -478,14 +532,9 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) {
 // parseHost parses host as an authority without user
 // information. That is, as host[:port].
 func parseHost(host string) (string, error) {
-       litOrName := host
        if strings.HasPrefix(host, "[") {
                // Parse an IP-Literal in RFC 3986 and RFC 6874.
-               // E.g., "[fe80::1], "[fe80::1%25en0]"
-               //
-               // RFC 4007 defines "%" as a delimiter character in
-               // the textual representation of IPv6 addresses.
-               // Per RFC 6874, in URIs that "%" is encoded as "%25".
+               // E.g., "[fe80::1]", "[fe80::1%25en0]", "[fe80::1]:80".
                i := strings.LastIndex(host, "]")
                if i < 0 {
                        return "", errors.New("missing ']' in host")
@@ -494,29 +543,31 @@ func parseHost(host string) (string, error) {
                if !validOptionalPort(colonPort) {
                        return "", fmt.Errorf("invalid port %q after host", colonPort)
                }
-               // Parse a host subcomponent without a ZoneID in RFC
-               // 6874 because the ZoneID is allowed to use the
-               // percent encoded form.
-               j := strings.Index(host[:i], "%25")
-               if j < 0 {
-                       litOrName = host[1:i]
-               } else {
-                       litOrName = host[1:j]
+
+               // RFC 6874 defines that %25 (%-encoded percent) introduces
+               // the zone identifier, and the zone identifier can use basically
+               // any %-encoding it likes. That's different from the host, which
+               // can only %-encode non-ASCII bytes.
+               // We do impose some restrictions on the zone, to avoid stupidity
+               // like newlines.
+               zone := strings.Index(host[:i], "%25")
+               if zone >= 0 {
+                       host1, err := unescape(host[:zone], encodeHost)
+                       if err != nil {
+                               return "", err
+                       }
+                       host2, err := unescape(host[zone:i], encodeZone)
+                       if err != nil {
+                               return "", err
+                       }
+                       host3, err := unescape(host[i:], encodeHost)
+                       if err != nil {
+                               return "", err
+                       }
+                       return host1 + host2 + host3, nil
                }
        }
 
-       // A URI containing an IP-Literal without a ZoneID or
-       // IPv4address in RFC 3986 and RFC 6847 must not be
-       // percent-encoded.
-       //
-       // A URI containing a DNS registered name in RFC 3986 is
-       // allowed to be percent-encoded, though we don't use it for
-       // now to avoid messing up with the gap between allowed
-       // characters in URI and allowed characters in DNS.
-       // See golang.org/issue/7991.
-       if strings.Contains(litOrName, "%") {
-               return "", errors.New("percent-encoded characters in host")
-       }
        var err error
        if host, err = unescape(host, encodeHost); err != nil {
                return "", err
@@ -572,12 +623,12 @@ func validEncodedPath(s string) bool {
 }
 
 // validOptionalPort reports whether port is either an empty string
-// or matches /^:\d+$/
+// or matches /^:\d*$/
 func validOptionalPort(port string) bool {
        if port == "" {
                return true
        }
-       if port[0] != ':' || len(port) == 1 {
+       if port[0] != ':' {
                return false
        }
        for _, b := range port[1:] {
@@ -596,7 +647,7 @@ func validOptionalPort(port string) bool {
 //
 // If u.Opaque is non-empty, String uses the first form;
 // otherwise it uses the second form.
-// To obtain the path, String uses u.EncodedPath().
+// To obtain the path, String uses u.EscapedPath().
 //
 // In the second form, the following rules apply:
 //     - if u.Scheme is empty, scheme: is omitted.
index ff6e9e4541a7b6b524f74e02808bedfc5f464406..d3f8487bd7c0addb96f8e7329f98619308589540 100644 (file)
@@ -6,6 +6,8 @@ package url
 
 import (
        "fmt"
+       "io"
+       "net"
        "reflect"
        "strings"
        "testing"
@@ -330,7 +332,7 @@ var urltests = []URLTest{
                },
                "",
        },
-       // host subcomponent; IPv6 address with zone identifier in RFC 6847
+       // host subcomponent; IPv6 address with zone identifier in RFC 6874
        {
                "http://[fe80::1%25en0]/", // alphanum zone identifier
                &URL{
@@ -340,7 +342,7 @@ var urltests = []URLTest{
                },
                "",
        },
-       // host and port subcomponents; IPv6 address with zone identifier in RFC 6847
+       // host and port subcomponents; IPv6 address with zone identifier in RFC 6874
        {
                "http://[fe80::1%25en0]:8080/", // alphanum zone identifier
                &URL{
@@ -350,7 +352,7 @@ var urltests = []URLTest{
                },
                "",
        },
-       // host subcomponent; IPv6 address with zone identifier in RFC 6847
+       // host subcomponent; IPv6 address with zone identifier in RFC 6874
        {
                "http://[fe80::1%25%65%6e%301-._~]/", // percent-encoded+unreserved zone identifier
                &URL{
@@ -360,7 +362,7 @@ var urltests = []URLTest{
                },
                "http://[fe80::1%25en01-._~]/",
        },
-       // host and port subcomponents; IPv6 address with zone identifier in RFC 6847
+       // host and port subcomponents; IPv6 address with zone identifier in RFC 6874
        {
                "http://[fe80::1%25%65%6e%301-._~]:8080/", // percent-encoded+unreserved zone identifier
                &URL{
@@ -424,6 +426,122 @@ var urltests = []URLTest{
                },
                "",
        },
+       // golang.org/issue/12200 (colon with empty port)
+       {
+               "http://192.168.0.2:8080/foo",
+               &URL{
+                       Scheme: "http",
+                       Host:   "192.168.0.2:8080",
+                       Path:   "/foo",
+               },
+               "",
+       },
+       {
+               "http://192.168.0.2:/foo",
+               &URL{
+                       Scheme: "http",
+                       Host:   "192.168.0.2:",
+                       Path:   "/foo",
+               },
+               "",
+       },
+       {
+               // Malformed IPv6 but still accepted.
+               "http://2b01:e34:ef40:7730:8e70:5aff:fefe:edac:8080/foo",
+               &URL{
+                       Scheme: "http",
+                       Host:   "2b01:e34:ef40:7730:8e70:5aff:fefe:edac:8080",
+                       Path:   "/foo",
+               },
+               "",
+       },
+       {
+               // Malformed IPv6 but still accepted.
+               "http://2b01:e34:ef40:7730:8e70:5aff:fefe:edac:/foo",
+               &URL{
+                       Scheme: "http",
+                       Host:   "2b01:e34:ef40:7730:8e70:5aff:fefe:edac:",
+                       Path:   "/foo",
+               },
+               "",
+       },
+       {
+               "http://[2b01:e34:ef40:7730:8e70:5aff:fefe:edac]:8080/foo",
+               &URL{
+                       Scheme: "http",
+                       Host:   "[2b01:e34:ef40:7730:8e70:5aff:fefe:edac]:8080",
+                       Path:   "/foo",
+               },
+               "",
+       },
+       {
+               "http://[2b01:e34:ef40:7730:8e70:5aff:fefe:edac]:/foo",
+               &URL{
+                       Scheme: "http",
+                       Host:   "[2b01:e34:ef40:7730:8e70:5aff:fefe:edac]:",
+                       Path:   "/foo",
+               },
+               "",
+       },
+       // golang.org/issue/7991 and golang.org/issue/12719 (non-ascii %-encoded in host)
+       {
+               "http://hello.世界.com/foo",
+               &URL{
+                       Scheme: "http",
+                       Host:   "hello.世界.com",
+                       Path:   "/foo",
+               },
+               "http://hello.%E4%B8%96%E7%95%8C.com/foo",
+       },
+       {
+               "http://hello.%e4%b8%96%e7%95%8c.com/foo",
+               &URL{
+                       Scheme: "http",
+                       Host:   "hello.世界.com",
+                       Path:   "/foo",
+               },
+               "http://hello.%E4%B8%96%E7%95%8C.com/foo",
+       },
+       {
+               "http://hello.%E4%B8%96%E7%95%8C.com/foo",
+               &URL{
+                       Scheme: "http",
+                       Host:   "hello.世界.com",
+                       Path:   "/foo",
+               },
+               "",
+       },
+       // golang.org/issue/10433 (path beginning with //)
+       {
+               "http://example.com//foo",
+               &URL{
+                       Scheme: "http",
+                       Host:   "example.com",
+                       Path:   "//foo",
+               },
+               "",
+       },
+       // test that we can reparse the host names we accept.
+       {
+               "myscheme://authority<\"hi\">/foo",
+               &URL{
+                       Scheme: "myscheme",
+                       Host:   "authority<\"hi\">",
+                       Path:   "/foo",
+               },
+               "",
+       },
+       // spaces in hosts are disallowed but escaped spaces in IPv6 scope IDs are grudgingly OK.
+       // This happens on Windows.
+       // golang.org/issue/14002
+       {
+               "tcp://[2020::2020:20:2020:2020%25Windows%20Loves%20Spaces]:2020",
+               &URL{
+                       Scheme: "tcp",
+                       Host:   "[2020::2020:20:2020:2020%Windows Loves Spaces]:2020",
+               },
+               "",
+       },
 }
 
 // more useful string for debugging than fmt's struct printer
@@ -1091,6 +1209,14 @@ var requritests = []RequestURITest{
                },
                "opaque?q=go+language",
        },
+       {
+               &URL{
+                       Scheme: "http",
+                       Host:   "example.com",
+                       Path:   "//foo",
+               },
+               "//foo",
+       },
 }
 
 func TestRequestURI(t *testing.T) {
@@ -1124,16 +1250,17 @@ func TestParseAuthority(t *testing.T) {
                {"http://[::1]a", true},
                {"http://[::1]%23", true},
                {"http://[::1%25en0]", false},     // valid zone id
-               {"http://[::1]:", true},           // colon, but no port
-               {"http://[::1]:%38%30", true},     // no hex in port
-               {"http://[::1%25%10]", false},     // TODO: reject the %10 after the valid zone %25 separator?
+               {"http://[::1]:", false},          // colon, but no port OK
+               {"http://[::1]:%38%30", true},     // not allowed: % encoding only for non-ASCII
+               {"http://[::1%25%41]", false},     // RFC 6874 allows over-escaping in zone
                {"http://[%10::1]", true},         // no %xx escapes in IP address
                {"http://[::1]/%48", false},       // %xx in path is fine
-               {"http://%41:8080/", true},        // TODO: arguably we should accept reg-name with %xx
+               {"http://%41:8080/", true},        // not allowed: % encoding only for non-ASCII
                {"mysql://x@y(z:123)/foo", false}, // golang.org/issue/12023
                {"mysql://x@y(1.2.3.4:123)/foo", false},
                {"mysql://x@y([2001:db8::1]:123)/foo", false},
                {"http://[]%20%48%54%54%50%2f%31%2e%31%0a%4d%79%48%65%61%64%65%72%3a%20%31%32%33%0a%0a/", true}, // golang.org/issue/11208
+               {"http://a b.com/", true},                                                                       // no space in host name please
        }
        for _, tt := range tests {
                u, err := Parse(tt.in)
@@ -1229,3 +1356,84 @@ func TestShouldEscape(t *testing.T) {
                }
        }
 }
+
+type timeoutError struct {
+       timeout bool
+}
+
+func (e *timeoutError) Error() string { return "timeout error" }
+func (e *timeoutError) Timeout() bool { return e.timeout }
+
+type temporaryError struct {
+       temporary bool
+}
+
+func (e *temporaryError) Error() string   { return "temporary error" }
+func (e *temporaryError) Temporary() bool { return e.temporary }
+
+type timeoutTemporaryError struct {
+       timeoutError
+       temporaryError
+}
+
+func (e *timeoutTemporaryError) Error() string { return "timeout/temporary error" }
+
+var netErrorTests = []struct {
+       err       error
+       timeout   bool
+       temporary bool
+}{{
+       err:       &Error{"Get", "http://google.com/", &timeoutError{timeout: true}},
+       timeout:   true,
+       temporary: false,
+}, {
+       err:       &Error{"Get", "http://google.com/", &timeoutError{timeout: false}},
+       timeout:   false,
+       temporary: false,
+}, {
+       err:       &Error{"Get", "http://google.com/", &temporaryError{temporary: true}},
+       timeout:   false,
+       temporary: true,
+}, {
+       err:       &Error{"Get", "http://google.com/", &temporaryError{temporary: false}},
+       timeout:   false,
+       temporary: false,
+}, {
+       err:       &Error{"Get", "http://google.com/", &timeoutTemporaryError{timeoutError{timeout: true}, temporaryError{temporary: true}}},
+       timeout:   true,
+       temporary: true,
+}, {
+       err:       &Error{"Get", "http://google.com/", &timeoutTemporaryError{timeoutError{timeout: false}, temporaryError{temporary: true}}},
+       timeout:   false,
+       temporary: true,
+}, {
+       err:       &Error{"Get", "http://google.com/", &timeoutTemporaryError{timeoutError{timeout: true}, temporaryError{temporary: false}}},
+       timeout:   true,
+       temporary: false,
+}, {
+       err:       &Error{"Get", "http://google.com/", &timeoutTemporaryError{timeoutError{timeout: false}, temporaryError{temporary: false}}},
+       timeout:   false,
+       temporary: false,
+}, {
+       err:       &Error{"Get", "http://google.com/", io.EOF},
+       timeout:   false,
+       temporary: false,
+}}
+
+// Test that url.Error implements net.Error and that it forwards
+func TestURLErrorImplementsNetError(t *testing.T) {
+       for i, tt := range netErrorTests {
+               err, ok := tt.err.(net.Error)
+               if !ok {
+                       t.Errorf("%d: %T does not implement net.Error", i+1, tt.err)
+                       continue
+               }
+               if err.Timeout() != tt.timeout {
+                       t.Errorf("%d: err.Timeout(): want %v, have %v", i+1, tt.timeout, err.Timeout())
+                       continue
+               }
+               if err.Temporary() != tt.temporary {
+                       t.Errorf("%d: err.Temporary(): want %v, have %v", i+1, tt.temporary, err.Temporary())
+               }
+       }
+}
index 8810e693067b239a4254872fd6d60ac17f432471..e26ce279706933393e2c21208d783527bb04d609 100644 (file)
@@ -10,7 +10,7 @@ import (
 
 // Portable analogs of some common system call errors.
 var (
-       ErrInvalid    = errors.New("invalid argument")
+       ErrInvalid    = errors.New("invalid argument") // methods on File will return this error when the receiver is nil
        ErrPermission = errors.New("permission denied")
        ErrExist      = errors.New("file already exists")
        ErrNotExist   = errors.New("file does not exist")
index 001cdfcf2e3376aed7273ddbd1a28c7b663b7995..2dc6b39c39595b43fe0aa134d5ad6e4c3b92c158 100644 (file)
@@ -12,6 +12,8 @@ func isExist(err error) bool {
                err = pe.Err
        case *LinkError:
                err = pe.Err
+       case *SyscallError:
+               err = pe.Err
        }
        return contains(err.Error(), " exists")
 }
@@ -24,6 +26,8 @@ func isNotExist(err error) bool {
                err = pe.Err
        case *LinkError:
                err = pe.Err
+       case *SyscallError:
+               err = pe.Err
        }
        return contains(err.Error(), "does not exist") || contains(err.Error(), "not found") ||
                contains(err.Error(), "has been removed") || contains(err.Error(), "no parent")
@@ -37,6 +41,8 @@ func isPermission(err error) bool {
                err = pe.Err
        case *LinkError:
                err = pe.Err
+       case *SyscallError:
+               err = pe.Err
        }
        return contains(err.Error(), "permission denied")
 }
index 02ed2351c5c0a95c91ce614a7b2fe9f26be7a1b7..5477e7ecbdbe6eddfe4f6aff4f03a7ec49ab995b 100644 (file)
@@ -93,6 +93,8 @@ var isExistTests = []struct {
        {&os.LinkError{Err: os.ErrPermission}, false, false},
        {&os.LinkError{Err: os.ErrExist}, true, false},
        {&os.LinkError{Err: os.ErrNotExist}, false, true},
+       {&os.SyscallError{Err: os.ErrNotExist}, false, true},
+       {&os.SyscallError{Err: os.ErrExist}, true, false},
        {nil, false, false},
 }
 
@@ -107,6 +109,23 @@ func TestIsExist(t *testing.T) {
        }
 }
 
+var isPermissionTests = []struct {
+       err  error
+       want bool
+}{
+       {nil, false},
+       {&os.PathError{Err: os.ErrPermission}, true},
+       {&os.SyscallError{Err: os.ErrPermission}, true},
+}
+
+func TestIsPermission(t *testing.T) {
+       for _, tt := range isPermissionTests {
+               if got := os.IsPermission(tt.err); got != tt.want {
+                       t.Errorf("os.IsPermission(%#v) = %v; want %v", tt.err, got, tt.want)
+               }
+       }
+}
+
 func TestErrPathNUL(t *testing.T) {
        f, err := ioutil.TempFile("", "_Go_ErrPathNUL\x00")
        if err == nil {
index f2aabbb45c43b5282ce97d1225cd08d568c826fd..c6002279da68314b579c7648c674668bbaad8db6 100644 (file)
@@ -16,6 +16,8 @@ func isExist(err error) bool {
                err = pe.Err
        case *LinkError:
                err = pe.Err
+       case *SyscallError:
+               err = pe.Err
        }
        return err == syscall.EEXIST || err == ErrExist
 }
@@ -28,6 +30,8 @@ func isNotExist(err error) bool {
                err = pe.Err
        case *LinkError:
                err = pe.Err
+       case *SyscallError:
+               err = pe.Err
        }
        return err == syscall.ENOENT || err == ErrNotExist
 }
@@ -40,6 +44,8 @@ func isPermission(err error) bool {
                err = pe.Err
        case *LinkError:
                err = pe.Err
+       case *SyscallError:
+               err = pe.Err
        }
        return err == syscall.EACCES || err == syscall.EPERM || err == ErrPermission
 }
index 83db6c07845333266d5c5ffabb3d05a9436056f7..2c1c39c414b1414b8dea1af3494619161aeb80be 100644 (file)
@@ -14,11 +14,15 @@ func isExist(err error) bool {
                err = pe.Err
        case *LinkError:
                err = pe.Err
+       case *SyscallError:
+               err = pe.Err
        }
        return err == syscall.ERROR_ALREADY_EXISTS ||
                err == syscall.ERROR_FILE_EXISTS || err == ErrExist
 }
 
+const _ERROR_BAD_NETPATH = syscall.Errno(53)
+
 func isNotExist(err error) bool {
        switch pe := err.(type) {
        case nil:
@@ -27,8 +31,11 @@ func isNotExist(err error) bool {
                err = pe.Err
        case *LinkError:
                err = pe.Err
+       case *SyscallError:
+               err = pe.Err
        }
        return err == syscall.ERROR_FILE_NOT_FOUND ||
+               err == _ERROR_BAD_NETPATH ||
                err == syscall.ERROR_PATH_NOT_FOUND || err == ErrNotExist
 }
 
@@ -40,6 +47,8 @@ func isPermission(err error) bool {
                err = pe.Err
        case *LinkError:
                err = pe.Err
+       case *SyscallError:
+               err = pe.Err
        }
        return err == syscall.ERROR_ACCESS_DENIED || err == ErrPermission
 }
index 8a84e263dc8bf013e424dbbade63b72fd5946633..340ebd498b7e7ab11441762d69b93b0a86c82cc7 100644 (file)
@@ -5,6 +5,10 @@
 // Package exec runs external commands. It wraps os.StartProcess to make it
 // easier to remap stdin and stdout, connect I/O with pipes, and do other
 // adjustments.
+//
+// Note that the examples in this package assume a Unix system.
+// They may not run on Windows, and they do not run in the Go Playground
+// used by golang.org and godoc.org.
 package exec
 
 import (
@@ -347,6 +351,18 @@ func (c *Cmd) Start() error {
 // An ExitError reports an unsuccessful exit by a command.
 type ExitError struct {
        *os.ProcessState
+
+       // Stderr holds a subset of the standard error output from the
+       // Cmd.Output method if standard error was not otherwise being
+       // collected.
+       //
+       // If the error output is long, Stderr may contain only a prefix
+       // and suffix of the output, with the middle replaced with
+       // text about the number of omitted bytes.
+       //
+       // Stderr is provided for debugging, for inclusion in error messages.
+       // Users with other needs should redirect Cmd.Stderr as needed.
+       Stderr []byte
 }
 
 func (e *ExitError) Error() string {
@@ -392,21 +408,34 @@ func (c *Cmd) Wait() error {
        if err != nil {
                return err
        } else if !state.Success() {
-               return &ExitError{state}
+               return &ExitError{ProcessState: state}
        }
 
        return copyError
 }
 
 // Output runs the command and returns its standard output.
+// Any returned error will usually be of type *ExitError.
+// If c.Stderr was nil, Output populates ExitError.Stderr.
 func (c *Cmd) Output() ([]byte, error) {
        if c.Stdout != nil {
                return nil, errors.New("exec: Stdout already set")
        }
-       var b bytes.Buffer
-       c.Stdout = &b
+       var stdout bytes.Buffer
+       c.Stdout = &stdout
+
+       captureErr := c.Stderr == nil
+       if captureErr {
+               c.Stderr = &prefixSuffixSaver{N: 32 << 10}
+       }
+
        err := c.Run()
-       return b.Bytes(), err
+       if err != nil && captureErr {
+               if ee, ok := err.(*ExitError); ok {
+                       ee.Stderr = c.Stderr.(*prefixSuffixSaver).Bytes()
+               }
+       }
+       return stdout.Bytes(), err
 }
 
 // CombinedOutput runs the command and returns its combined standard
@@ -514,3 +543,80 @@ func (c *Cmd) StderrPipe() (io.ReadCloser, error) {
        c.closeAfterWait = append(c.closeAfterWait, pr)
        return pr, nil
 }
+
+// prefixSuffixSaver is an io.Writer which retains the first N bytes
+// and the last N bytes written to it. The Bytes() methods reconstructs
+// it with a pretty error message.
+type prefixSuffixSaver struct {
+       N         int // max size of prefix or suffix
+       prefix    []byte
+       suffix    []byte // ring buffer once len(suffix) == N
+       suffixOff int    // offset to write into suffix
+       skipped   int64
+
+       // TODO(bradfitz): we could keep one large []byte and use part of it for
+       // the prefix, reserve space for the '... Omitting N bytes ...' message,
+       // then the ring buffer suffix, and just rearrange the ring buffer
+       // suffix when Bytes() is called, but it doesn't seem worth it for
+       // now just for error messages. It's only ~64KB anyway.
+}
+
+func (w *prefixSuffixSaver) Write(p []byte) (n int, err error) {
+       lenp := len(p)
+       p = w.fill(&w.prefix, p)
+
+       // Only keep the last w.N bytes of suffix data.
+       if overage := len(p) - w.N; overage > 0 {
+               p = p[overage:]
+               w.skipped += int64(overage)
+       }
+       p = w.fill(&w.suffix, p)
+
+       // w.suffix is full now if p is non-empty. Overwrite it in a circle.
+       for len(p) > 0 { // 0, 1, or 2 iterations.
+               n := copy(w.suffix[w.suffixOff:], p)
+               p = p[n:]
+               w.skipped += int64(n)
+               w.suffixOff += n
+               if w.suffixOff == w.N {
+                       w.suffixOff = 0
+               }
+       }
+       return lenp, nil
+}
+
+// fill appends up to len(p) bytes of p to *dst, such that *dst does not
+// grow larger than w.N. It returns the un-appended suffix of p.
+func (w *prefixSuffixSaver) fill(dst *[]byte, p []byte) (pRemain []byte) {
+       if remain := w.N - len(*dst); remain > 0 {
+               add := minInt(len(p), remain)
+               *dst = append(*dst, p[:add]...)
+               p = p[add:]
+       }
+       return p
+}
+
+func (w *prefixSuffixSaver) Bytes() []byte {
+       if w.suffix == nil {
+               return w.prefix
+       }
+       if w.skipped == 0 {
+               return append(w.prefix, w.suffix...)
+       }
+       var buf bytes.Buffer
+       buf.Grow(len(w.prefix) + len(w.suffix) + 50)
+       buf.Write(w.prefix)
+       buf.WriteString("\n... omitting ")
+       buf.WriteString(strconv.FormatInt(w.skipped, 10))
+       buf.WriteString(" bytes ...\n")
+       buf.Write(w.suffix[w.suffixOff:])
+       buf.Write(w.suffix[:w.suffixOff])
+       return buf.Bytes()
+}
+
+func minInt(a, b int) int {
+       if a < b {
+               return a
+       }
+       return b
+}
index f4c025e839fff3881fb56e90cfe67e93f975aa9b..1576e8f1567c2bb7a975f0e98c3b87a0a32528bf 100644 (file)
@@ -764,6 +764,9 @@ func TestHelperProcess(*testing.T) {
                }
                fmt.Print(p)
                os.Exit(0)
+       case "stderrfail":
+               fmt.Fprintf(os.Stderr, "some stderr text\n")
+               os.Exit(1)
        default:
                fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd)
                os.Exit(2)
@@ -820,3 +823,19 @@ func TestClosePipeOnCopyError(t *testing.T) {
                t.Fatalf("yes got stuck writing to bad writer")
        }
 }
+
+func TestOutputStderrCapture(t *testing.T) {
+       testenv.MustHaveExec(t)
+
+       cmd := helperCommand(t, "stderrfail")
+       _, err := cmd.Output()
+       ee, ok := err.(*exec.ExitError)
+       if !ok {
+               t.Fatalf("Output error type = %T; want ExitError", err)
+       }
+       got := string(ee.Stderr)
+       want := "some stderr text\n"
+       if got != want {
+               t.Errorf("ExitError.Stderr = %q; want %q", got, want)
+       }
+}
diff --git a/libgo/go/os/exec/internal_test.go b/libgo/go/os/exec/internal_test.go
new file mode 100644 (file)
index 0000000..68d517f
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright 2015 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 exec
+
+import (
+       "io"
+       "testing"
+)
+
+func TestPrefixSuffixSaver(t *testing.T) {
+       tests := []struct {
+               N      int
+               writes []string
+               want   string
+       }{
+               {
+                       N:      2,
+                       writes: nil,
+                       want:   "",
+               },
+               {
+                       N:      2,
+                       writes: []string{"a"},
+                       want:   "a",
+               },
+               {
+                       N:      2,
+                       writes: []string{"abc", "d"},
+                       want:   "abcd",
+               },
+               {
+                       N:      2,
+                       writes: []string{"abc", "d", "e"},
+                       want:   "ab\n... omitting 1 bytes ...\nde",
+               },
+               {
+                       N:      2,
+                       writes: []string{"ab______________________yz"},
+                       want:   "ab\n... omitting 22 bytes ...\nyz",
+               },
+               {
+                       N:      2,
+                       writes: []string{"ab_______________________y", "z"},
+                       want:   "ab\n... omitting 23 bytes ...\nyz",
+               },
+       }
+       for i, tt := range tests {
+               w := &prefixSuffixSaver{N: tt.N}
+               for _, s := range tt.writes {
+                       n, err := io.WriteString(w, s)
+                       if err != nil || n != len(s) {
+                               t.Errorf("%d. WriteString(%q) = %v, %v; want %v, %v", i, s, n, err, len(s), nil)
+                       }
+               }
+               if got := string(w.Bytes()); got != tt.want {
+                       t.Errorf("%d. Bytes = %q; want %q", i, got, tt.want)
+               }
+       }
+}
index 8c0e3ffe1ba7dd7fc86fe06aac0723a121e85424..4f8e3f3450c0e5859416eff2b258abfb29716c38 100644 (file)
@@ -52,8 +52,8 @@ var (
        Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
 )
 
-// Flags to Open wrapping those of the underlying system. Not all flags
-// may be implemented on a given system.
+// Flags to OpenFile wrapping those of the underlying system. Not all
+// flags may be implemented on a given system.
 const (
        O_RDONLY int = syscall.O_RDONLY // open the file read-only.
        O_WRONLY int = syscall.O_WRONLY // open the file write-only.
@@ -93,9 +93,6 @@ func (f *File) Read(b []byte) (n int, err error) {
                return 0, ErrInvalid
        }
        n, e := f.read(b)
-       if n < 0 {
-               n = 0
-       }
        if n == 0 && len(b) > 0 && e == nil {
                return 0, io.EOF
        }
@@ -176,6 +173,7 @@ func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
 // according to whence: 0 means relative to the origin of the file, 1 means
 // relative to the current offset, and 2 means relative to the end.
 // It returns the new offset and an error, if any.
+// The behavior of Seek on a file opened with O_APPEND is not specified.
 func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
        if f == nil {
                return 0, ErrInvalid
@@ -258,7 +256,9 @@ func Create(name string) (*File, error) {
 // lstat is overridden in tests.
 var lstat = Lstat
 
-// Rename renames (moves) a file. OS-specific restrictions might apply.
+// Rename renames (moves) oldpath to newpath.
+// If newpath already exists, Rename replaces it.
+// OS-specific restrictions may apply when oldpath and newpath are in different directories.
 // If there is an error, it will be of type *LinkError.
 func Rename(oldpath, newpath string) error {
        return rename(oldpath, newpath)
index 085ebc4c8a649f300027e7d37232970d749e644e..c83fa028b991bba71ecddc889b7b6e4e95a84d79 100644 (file)
@@ -339,7 +339,9 @@ func rename(oldname, newname string) error {
 
        // If newname still contains slashes after removing the oldname
        // prefix, the rename is cross-directory and must be rejected.
-       // This case is caught by d.Marshal below.
+       if lastIndex(newname, '/') >= 0 {
+               return &LinkError{"rename", oldname, newname, ErrInvalid}
+       }
 
        var d syscall.Dir
 
@@ -351,6 +353,13 @@ func rename(oldname, newname string) error {
        if err != nil {
                return &LinkError{"rename", oldname, newname, err}
        }
+
+       // If newname already exists and is not a directory, rename replaces it.
+       f, err := Stat(dirname + newname)
+       if err == nil && !f.IsDir() {
+               Remove(dirname + newname)
+       }
+
        if err = syscall.Wstat(oldname, buf[:n]); err != nil {
                return &LinkError{"rename", oldname, newname, err}
        }
index 7a18987d283f42db916596377c2a7c7984642d14..c3119cd459f0fcaa095bb2b145a6a6436b53eef8 100644 (file)
@@ -8,10 +8,13 @@ package os
 
 import (
        "runtime"
-       "sync/atomic"
        "syscall"
 )
 
+func sameFile(fs1, fs2 *fileStat) bool {
+       return fs1.sys.Dev == fs2.sys.Dev && fs1.sys.Ino == fs2.sys.Ino
+}
+
 func rename(oldname, newname string) error {
        e := syscall.Rename(oldname, newname)
        if e != nil {
@@ -33,7 +36,6 @@ type file struct {
        fd      int
        name    string
        dirinfo *dirInfo // nil unless directory being read
-       nepipe  int32    // number of consecutive EPIPE in Write
 }
 
 // Fd returns the integer Unix file descriptor referencing the open file.
@@ -62,13 +64,12 @@ type dirInfo struct {
        dir *syscall.DIR // from opendir
 }
 
+// epipecheck raises SIGPIPE if we get an EPIPE error on standard
+// output or standard error. See the SIGPIPE docs in os/signal, and
+// issue 11845.
 func epipecheck(file *File, e error) {
-       if e == syscall.EPIPE {
-               if atomic.AddInt32(&file.nepipe, 1) >= 10 {
-                       sigpipe()
-               }
-       } else {
-               atomic.StoreInt32(&file.nepipe, 0)
+       if e == syscall.EPIPE && (file.fd == 1 || file.fd == 2) {
+               sigpipe()
        }
 }
 
@@ -89,8 +90,21 @@ func OpenFile(name string, flag int, perm FileMode) (*File, error) {
                }
        }
 
-       r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
-       if e != nil {
+       var r int
+       for {
+               var e error
+               r, e = syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
+               if e == nil {
+                       break
+               }
+
+               // On OS X, sigaction(2) doesn't guarantee that SA_RESTART will cause
+               // open(2) to be restarted for regular files. This is easy to reproduce on
+               // fuse file systems (see http://golang.org/issue/11180).
+               if runtime.GOOS == "darwin" && e == syscall.EINTR {
+                       continue
+               }
+
                return nil, &PathError{"open", name, e}
        }
 
@@ -150,23 +164,25 @@ func (f *File) Stat() (FileInfo, error) {
        if f == nil {
                return nil, ErrInvalid
        }
-       var stat syscall.Stat_t
-       err := syscall.Fstat(f.fd, &stat)
+       var fs fileStat
+       err := syscall.Fstat(f.fd, &fs.sys)
        if err != nil {
                return nil, &PathError{"stat", f.name, err}
        }
-       return fileInfoFromStat(&stat, f.name), nil
+       fillFileStatFromSys(&fs, f.name)
+       return &fs, nil
 }
 
 // Stat returns a FileInfo describing the named file.
 // If there is an error, it will be of type *PathError.
 func Stat(name string) (FileInfo, error) {
-       var stat syscall.Stat_t
-       err := syscall.Stat(name, &stat)
+       var fs fileStat
+       err := syscall.Stat(name, &fs.sys)
        if err != nil {
                return nil, &PathError{"stat", name, err}
        }
-       return fileInfoFromStat(&stat, name), nil
+       fillFileStatFromSys(&fs, name)
+       return &fs, nil
 }
 
 // Lstat returns a FileInfo describing the named file.
@@ -174,12 +190,13 @@ func Stat(name string) (FileInfo, error) {
 // describes the symbolic link.  Lstat makes no attempt to follow the link.
 // If there is an error, it will be of type *PathError.
 func Lstat(name string) (FileInfo, error) {
-       var stat syscall.Stat_t
-       err := syscall.Lstat(name, &stat)
+       var fs fileStat
+       err := syscall.Lstat(name, &fs.sys)
        if err != nil {
                return nil, &PathError{"lstat", name, err}
        }
-       return fileInfoFromStat(&stat, name), nil
+       fillFileStatFromSys(&fs, name)
+       return &fs, nil
 }
 
 func (f *File) readdir(n int) (fi []FileInfo, err error) {
index 78201f2c27e40a962aaf18410940d44c5c445a13..5497704e16787a1844fc1a309577ad0516593eb1 100644 (file)
@@ -45,10 +45,10 @@ var sysdir = func() *sysDir {
        switch runtime.GOOS {
        case "android":
                return &sysDir{
-                       "/system/etc",
+                       "/system/framework",
                        []string{
-                               "audio_policy.conf",
-                               "system_fonts.xml",
+                               "ext.jar",
+                               "framework.jar",
                        },
                }
        case "darwin":
@@ -294,6 +294,48 @@ func TestReaddir(t *testing.T) {
        testReaddir(sysdir.name, sysdir.files, t)
 }
 
+func benchmarkReaddirname(path string, b *testing.B) {
+       var nentries int
+       for i := 0; i < b.N; i++ {
+               f, err := Open(path)
+               if err != nil {
+                       b.Fatalf("open %q failed: %v", path, err)
+               }
+               ns, err := f.Readdirnames(-1)
+               f.Close()
+               if err != nil {
+                       b.Fatalf("readdirnames %q failed: %v", path, err)
+               }
+               nentries = len(ns)
+       }
+       b.Logf("benchmarkReaddirname %q: %d entries", path, nentries)
+}
+
+func benchmarkReaddir(path string, b *testing.B) {
+       var nentries int
+       for i := 0; i < b.N; i++ {
+               f, err := Open(path)
+               if err != nil {
+                       b.Fatalf("open %q failed: %v", path, err)
+               }
+               fs, err := f.Readdir(-1)
+               f.Close()
+               if err != nil {
+                       b.Fatalf("readdir %q failed: %v", path, err)
+               }
+               nentries = len(fs)
+       }
+       b.Logf("benchmarkReaddir %q: %d entries", path, nentries)
+}
+
+func BenchmarkReaddirname(b *testing.B) {
+       benchmarkReaddirname(".", b)
+}
+
+func BenchmarkReaddir(b *testing.B) {
+       benchmarkReaddir(".", b)
+}
+
 // Read the directory one entry at a time.
 func smallReaddirnames(file *File, length int, t *testing.T) []string {
        names := make([]string, length)
@@ -539,6 +581,12 @@ func TestHardLink(t *testing.T) {
        if runtime.GOOS == "plan9" {
                t.Skip("skipping on plan9, hardlinks not supported")
        }
+       // From Android release M (Marshmallow), hard linking files is blocked
+       // and an attempt to call link() on a file will return EACCES.
+       // - https://code.google.com/p/android-developer-preview/issues/detail?id=3150
+       if runtime.GOOS == "android" {
+               t.Skip("skipping on android, hardlinks not supported")
+       }
        defer chtmpdir(t)()
        from, to := "hardlinktestfrom", "hardlinktestto"
        Remove(from) // Just in case.
@@ -670,7 +718,7 @@ func TestSymlink(t *testing.T) {
 
 func TestLongSymlink(t *testing.T) {
        switch runtime.GOOS {
-       case "plan9", "nacl":
+       case "android", "plan9", "nacl":
                t.Skipf("skipping on %s", runtime.GOOS)
        case "windows":
                if !supportsSymlinks {
@@ -723,9 +771,6 @@ func TestRename(t *testing.T) {
 }
 
 func TestRenameOverwriteDest(t *testing.T) {
-       if runtime.GOOS == "plan9" {
-               t.Skip("skipping on plan9")
-       }
        defer chtmpdir(t)()
        from, to := "renamefrom", "renameto"
        // Just in case.
index 2adc3b50e727cdb5952d5c39c3cb009cb971390f..d02e07b478a5ccfcba237484c686c18ab59a92f0 100644 (file)
@@ -18,16 +18,16 @@ func init() {
 }
 
 func checkUidGid(t *testing.T, path string, uid, gid int) {
-       dir, err := Stat(path)
+       dir, err := Lstat(path)
        if err != nil {
-               t.Fatalf("Stat %q (looking for uid/gid %d/%d): %s", path, uid, gid, err)
+               t.Fatalf("Lstat %q (looking for uid/gid %d/%d): %s", path, uid, gid, err)
        }
        sys := dir.Sys().(*syscall.Stat_t)
        if int(sys.Uid) != uid {
-               t.Errorf("Stat %q: uid %d want %d", path, sys.Uid, uid)
+               t.Errorf("Lstat %q: uid %d want %d", path, sys.Uid, uid)
        }
        if int(sys.Gid) != gid {
-               t.Errorf("Stat %q: gid %d want %d", path, sys.Gid, gid)
+               t.Errorf("Lstat %q: gid %d want %d", path, sys.Gid, gid)
        }
 }
 
@@ -144,17 +144,11 @@ func TestLchown(t *testing.T) {
        }
 
        linkname := f.Name() + "2"
-       if err := Link(f.Name(), linkname); err != nil {
+       if err := Symlink(f.Name(), linkname); err != nil {
                t.Fatalf("link %s -> %s: %v", f.Name(), linkname, err)
        }
        defer Remove(linkname)
 
-       f2, err := Open(linkname)
-       if err != nil {
-               t.Fatalf("open %s: %v", linkname, err)
-       }
-       defer f2.Close()
-
        // Can't change uid unless root, but can try
        // changing the group id.  First try our current group.
        gid := Getgid()
@@ -177,10 +171,7 @@ func TestLchown(t *testing.T) {
                }
                checkUidGid(t, linkname, int(sys.Uid), g)
 
-               // change back to gid to test fd.Chown
-               if err = f2.Chown(-1, gid); err != nil {
-                       t.Fatalf("fchown %s -1 %d: %s", linkname, gid, err)
-               }
-               checkUidGid(t, linkname, int(sys.Uid), gid)
+               // Check that link target's gid is unchanged.
+               checkUidGid(t, f.Name(), int(sys.Uid), int(sys.Gid))
        }
 }
index f9853810c6f793937e297b182e528140bd304c42..b4531314d04e1302aebdf010f2ee3721bf01986d 100644 (file)
@@ -170,7 +170,7 @@ func TestRemoveAll(t *testing.T) {
 
 func TestMkdirAllWithSymlink(t *testing.T) {
        switch runtime.GOOS {
-       case "nacl", "plan9":
+       case "android", "nacl", "plan9":
                t.Skipf("skipping on %s", runtime.GOOS)
        case "windows":
                if !supportsSymlinks {
diff --git a/libgo/go/os/pipe_test.go b/libgo/go/os/pipe_test.go
new file mode 100644 (file)
index 0000000..82b792e
--- /dev/null
@@ -0,0 +1,113 @@
+// Copyright 2015 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 broken pipes on Unix systems.
+// +build !windows,!plan9,!nacl
+
+package os_test
+
+import (
+       "fmt"
+       "internal/testenv"
+       "os"
+       osexec "os/exec"
+       "os/signal"
+       "syscall"
+       "testing"
+)
+
+func TestEPIPE(t *testing.T) {
+       r, w, err := os.Pipe()
+       if err != nil {
+               t.Fatal(err)
+       }
+       if err := r.Close(); err != nil {
+               t.Fatal(err)
+       }
+
+       // Every time we write to the pipe we should get an EPIPE.
+       for i := 0; i < 20; i++ {
+               _, err = w.Write([]byte("hi"))
+               if err == nil {
+                       t.Fatal("unexpected success of Write to broken pipe")
+               }
+               if pe, ok := err.(*os.PathError); ok {
+                       err = pe.Err
+               }
+               if se, ok := err.(*os.SyscallError); ok {
+                       err = se.Err
+               }
+               if err != syscall.EPIPE {
+                       t.Errorf("iteration %d: got %v, expected EPIPE", i, err)
+               }
+       }
+}
+
+func TestStdPipe(t *testing.T) {
+       testenv.MustHaveExec(t)
+       r, w, err := os.Pipe()
+       if err != nil {
+               t.Fatal(err)
+       }
+       if err := r.Close(); err != nil {
+               t.Fatal(err)
+       }
+       // Invoke the test program to run the test and write to a closed pipe.
+       // If sig is false:
+       // writing to stdout or stderr should cause an immediate SIGPIPE;
+       // writing to descriptor 3 should fail with EPIPE and then exit 0.
+       // If sig is true:
+       // all writes should fail with EPIPE and then exit 0.
+       for _, sig := range []bool{false, true} {
+               for dest := 1; dest < 4; dest++ {
+                       cmd := osexec.Command(os.Args[0], "-test.run", "TestStdPipeHelper")
+                       cmd.Stdout = w
+                       cmd.Stderr = w
+                       cmd.ExtraFiles = []*os.File{w}
+                       cmd.Env = append(os.Environ(), fmt.Sprintf("GO_TEST_STD_PIPE_HELPER=%d", dest))
+                       if sig {
+                               cmd.Env = append(cmd.Env, "GO_TEST_STD_PIPE_HELPER_SIGNAL=1")
+                       }
+                       if err := cmd.Run(); err == nil {
+                               if !sig && dest < 3 {
+                                       t.Errorf("unexpected success of write to closed pipe %d sig %t in child", dest, sig)
+                               }
+                       } else if ee, ok := err.(*osexec.ExitError); !ok {
+                               t.Errorf("unexpected exec error type %T: %v", err, err)
+                       } else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
+                               t.Errorf("unexpected wait status type %T: %v", ee.Sys(), ee.Sys())
+                       } else if ws.Signaled() && ws.Signal() == syscall.SIGPIPE {
+                               if sig || dest > 2 {
+                                       t.Errorf("unexpected SIGPIPE signal for descriptor %d sig %t", dest, sig)
+                               }
+                       } else {
+                               t.Errorf("unexpected exit status %v for descriptor %ds sig %t", err, dest, sig)
+                       }
+               }
+       }
+}
+
+// This is a helper for TestStdPipe.  It's not a test in itself.
+func TestStdPipeHelper(t *testing.T) {
+       if os.Getenv("GO_TEST_STD_PIPE_HELPER_SIGNAL") != "" {
+               signal.Notify(make(chan os.Signal, 1), syscall.SIGPIPE)
+       }
+       switch os.Getenv("GO_TEST_STD_PIPE_HELPER") {
+       case "1":
+               os.Stdout.Write([]byte("stdout"))
+       case "2":
+               os.Stderr.Write([]byte("stderr"))
+       case "3":
+               if _, err := os.NewFile(3, "3").Write([]byte("3")); err == nil {
+                       os.Exit(3)
+               }
+       default:
+               t.Skip("skipping test helper")
+       }
+       // For stdout/stderr, we should have crashed with a broken pipe error.
+       // The caller will be looking for that exit status,
+       // so just exit normally here to cause a failure in the caller.
+       // For descriptor 3, a normal exit is expected.
+       os.Exit(0)
+}
diff --git a/libgo/go/os/signal/doc.go b/libgo/go/os/signal/doc.go
new file mode 100644 (file)
index 0000000..80e66cf
--- /dev/null
@@ -0,0 +1,220 @@
+// Copyright 2015 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 signal implements access to incoming signals.
+
+Signals are primarily used on Unix-like systems. For the use of this
+package on Windows and Plan 9, see below.
+
+Types of signals
+
+The signals SIGKILL and SIGSTOP may not be caught by a program, and
+therefore can not be affected by this package.
+
+Synchronous signals are signals triggered by errors in program
+execution: SIGBUS, SIGFPE, and SIGSEGV. These are only considered
+synchronous when caused by program execution, not when sent using
+os.Process.Kill or the kill program or some similar mechanism. In
+general, except as discussed below, Go programs will convert a
+synchronous signal into a run-time panic.
+
+The remaining signals are asynchronous signals. They are not
+triggered by program errors, but are instead sent from the kernel or
+from some other program.
+
+Of the asynchronous signals, the SIGHUP signal is sent when a program
+loses its controlling terminal. The SIGINT signal is sent when the
+user at the controlling terminal presses the interrupt character,
+which by default is ^C (Control-C). The SIGQUIT signal is sent when
+the user at the controlling terminal presses the quit character, which
+by default is ^\ (Control-Backslash). In general you can cause a
+program to simply exit by pressing ^C, and you can cause it to exit
+with a stack dump by pressing ^\.
+
+Default behavior of signals in Go programs
+
+By default, a synchronous signal is converted into a run-time panic. A
+SIGHUP, SIGINT, or SIGTERM signal causes the program to exit. A
+SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGSTKFLT, SIGEMT, or SIGSYS signal
+causes the program to exit with a stack dump. A SIGTSTP, SIGTTIN, or
+SIGTTOU signal gets the system default behavior (these signals are
+used by the shell for job control). The SIGPROF signal is handled
+directly by the Go runtime to implement runtime.CPUProfile. Other
+signals will be caught but no action will be taken.
+
+If the Go program is started with either SIGHUP or SIGINT ignored
+(signal handler set to SIG_IGN), they will remain ignored.
+
+If the Go program is started with a non-empty signal mask, that will
+generally be honored. However, some signals are explicitly unblocked:
+the synchronous signals, SIGILL, SIGTRAP, SIGSTKFLT, SIGCHLD, SIGPROF,
+and, on GNU/Linux, signals 32 (SIGCANCEL) and 33 (SIGSETXID)
+(SIGCANCEL and SIGSETXID are used internally by glibc). Subprocesses
+started by os.Exec, or by the os/exec package, will inherit the
+modified signal mask.
+
+Changing the behavior of signals in Go programs
+
+The functions in this package allow a program to change the way Go
+programs handle signals.
+
+Notify disables the default behavior for a given set of asynchronous
+signals and instead delivers them over one or more registered
+channels. Specifically, it applies to the signals SIGHUP, SIGINT,
+SIGQUIT, SIGABRT, and SIGTERM. It also applies to the job control
+signals SIGTSTP, SIGTTIN, and SIGTTOU, in which case the system
+default behavior does not occur. It also applies to some signals that
+otherwise cause no action: SIGUSR1, SIGUSR2, SIGPIPE, SIGALRM,
+SIGCHLD, SIGCONT, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGWINCH,
+SIGIO, SIGPWR, SIGSYS, SIGINFO, SIGTHR, SIGWAITING, SIGLWP, SIGFREEZE,
+SIGTHAW, SIGLOST, SIGXRES, SIGJVM1, SIGJVM2, and any real time signals
+used on the system. Note that not all of these signals are available
+on all systems.
+
+If the program was started with SIGHUP or SIGINT ignored, and Notify
+is called for either signal, a signal handler will be installed for
+that signal and it will no longer be ignored. If, later, Reset or
+Ignore is called for that signal, or Stop is called on all channels
+passed to Notify for that signal, the signal will once again be
+ignored. Reset will restore the system default behavior for the
+signal, while Ignore will cause the system to ignore the signal
+entirely.
+
+If the program is started with a non-empty signal mask, some signals
+will be explicitly unblocked as described above. If Notify is called
+for a blocked signal, it will be unblocked. If, later, Reset is
+called for that signal, or Stop is called on all channels passed to
+Notify for that signal, the signal will once again be blocked.
+
+SIGPIPE
+
+When a Go program writes to a broken pipe, the kernel will raise a
+SIGPIPE signal.
+
+If the program has not called Notify to receive SIGPIPE signals, then
+the behavior depends on the file descriptor number. A write to a
+broken pipe on file descriptors 1 or 2 (standard output or standard
+error) will cause the program to exit with a SIGPIPE signal. A write
+to a broken pipe on some other file descriptor will take no action on
+the SIGPIPE signal, and the write will fail with an EPIPE error.
+
+If the program has called Notify to receive SIGPIPE signals, the file
+descriptor number does not matter. The SIGPIPE signal will be
+delivered to the Notify channel, and the write will fail with an EPIPE
+error.
+
+This means that, by default, command line programs will behave like
+typical Unix command line programs, while other programs will not
+crash with SIGPIPE when writing to a closed network connection.
+
+Go programs that use cgo or SWIG
+
+In a Go program that includes non-Go code, typically C/C++ code
+accessed using cgo or SWIG, Go's startup code normally runs first. It
+configures the signal handlers as expected by the Go runtime, before
+the non-Go startup code runs. If the non-Go startup code wishes to
+install its own signal handlers, it must take certain steps to keep Go
+working well. This section documents those steps and the overall
+effect changes to signal handler settings by the non-Go code can have
+on Go programs. In rare cases, the non-Go code may run before the Go
+code, in which case the next section also applies.
+
+If the non-Go code called by the Go program does not change any signal
+handlers or masks, then the behavior is the same as for a pure Go
+program.
+
+If the non-Go code installs any signal handlers, it must use the
+SA_ONSTACK flag with sigaction. Failing to do so is likely to cause
+the program to crash if the signal is received. Go programs routinely
+run with a limited stack, and therefore set up an alternate signal
+stack. Also, the Go standard library expects that any signal handlers
+will use the SA_RESTART flag. Failing to do so may cause some library
+calls to return "interrupted system call" errors.
+
+If the non-Go code installs a signal handler for any of the
+synchronous signals (SIGBUS, SIGFPE, SIGSEGV), then it should record
+the existing Go signal handler. If those signals occur while
+executing Go code, it should invoke the Go signal handler (whether the
+signal occurs while executing Go code can be determined by looking at
+the PC passed to the signal handler). Otherwise some Go run-time
+panics will not occur as expected.
+
+If the non-Go code installs a signal handler for any of the
+asynchronous signals, it may invoke the Go signal handler or not as it
+chooses. Naturally, if it does not invoke the Go signal handler, the
+Go behavior described above will not occur. This can be an issue with
+the SIGPROF signal in particular.
+
+The non-Go code should not change the signal mask on any threads
+created by the Go runtime. If the non-Go code starts new threads of
+its own, it may set the signal mask as it pleases.
+
+If the non-Go code starts a new thread, changes the signal mask, and
+then invokes a Go function in that thread, the Go runtime will
+automatically unblock certain signals: the synchronous signals,
+SIGILL, SIGTRAP, SIGSTKFLT, SIGCHLD, SIGPROF, SIGCANCEL, and
+SIGSETXID. When the Go function returns, the non-Go signal mask will
+be restored.
+
+If the Go signal handler is invoked on a non-Go thread not running Go
+code, the handler generally forwards the signal to the non-Go code, as
+follows. If the signal is SIGPROF, the Go handler does
+nothing. Otherwise, the Go handler removes itself, unblocks the
+signal, and raises it again, to invoke any non-Go handler or default
+system handler. If the program does not exit, the Go handler then
+reinstalls itself and continues execution of the program.
+
+Non-Go programs that call Go code
+
+When Go code is built with options like -buildmode=c-shared, it will
+be run as part of an existing non-Go program. The non-Go code may
+have already installed signal handlers when the Go code starts (that
+may also happen in unusual cases when using cgo or SWIG; in that case,
+the discussion here applies).  For -buildmode=c-archive the Go runtime
+will initialize signals at global constructor time.  For
+-buildmode=c-shared the Go runtime will initialize signals when the
+shared library is loaded.
+
+If the Go runtime sees an existing signal handler for the SIGCANCEL or
+SIGSETXID signals (which are used only on GNU/Linux), it will turn on
+the SA_ONSTACK flag and otherwise keep the signal handler.
+
+For the synchronous signals, the Go runtime will install a signal
+handler. It will save any existing signal handler. If a synchronous
+signal arrives while executing non-Go code, the Go runtime will invoke
+the existing signal handler instead of the Go signal handler.
+
+Go code built with -buildmode=c-archive or -buildmode=c-shared will
+not install any other signal handlers by default. If there is an
+existing signal handler, the Go runtime will turn on the SA_ONSTACK
+flag and otherwise keep the signal handler. If Notify is called for an
+asynchronous signal, a Go signal handler will be installed for that
+signal. If, later, Reset is called for that signal, the original
+handling for that signal will be reinstalled, restoring the non-Go
+signal handler if any.
+
+Go code built without -buildmode=c-archive or -buildmode=c-shared will
+install a signal handler for the asynchronous signals listed above,
+and save any existing signal handler. If a signal is delivered to a
+non-Go thread, it will act as described above, except that if there is
+an existing non-Go signal handler, that handler will be installed
+before raising the signal.
+
+Windows
+
+On Windows a ^C (Control-C) or ^BREAK (Control-Break) normally cause
+the program to exit. If Notify is called for os.SIGINT, ^C or ^BREAK
+will cause os.SIGINT to be sent on the channel, and the program will
+not exit. If Reset is called, or Stop is called on all channels passed
+to Notify, then the default behavior will be restored.
+
+Plan 9
+
+On Plan 9, signals have type syscall.Note, which is a string. Calling
+Notify with a syscall.Note will cause that value to be sent on the
+channel when that string is posted as a note.
+
+*/
+package signal
index 1625786d490ee11fab3a08c5b853cfb668976d0a..2e6f18665837c91b6b5f0f2fa185fbea9583d4c9 100644 (file)
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package signal implements access to incoming signals.
 package signal
 
 import (
index a71633c8907b98d9a624e04fdb3b2f9ca0b10c8c..56d786e501558e387d763e742f13f7bbe0a4a455 100644 (file)
@@ -182,13 +182,14 @@ func TestStop(t *testing.T) {
        sigs := []syscall.Signal{
                syscall.SIGWINCH,
                syscall.SIGHUP,
+               syscall.SIGUSR1,
        }
 
        for _, sig := range sigs {
                // Send the signal.
                // If it's SIGWINCH, we should not see it.
                // If it's SIGHUP, maybe we'll die. Let the flag tell us what to do.
-               if sig != syscall.SIGHUP || *sendUncaughtSighup == 1 {
+               if sig == syscall.SIGWINCH || (sig == syscall.SIGHUP && *sendUncaughtSighup == 1) {
                        syscall.Kill(syscall.Getpid(), sig)
                }
                time.Sleep(100 * time.Millisecond)
@@ -255,6 +256,12 @@ func TestNohup(t *testing.T) {
 
        Stop(c)
 
+       // Skip the nohup test below when running in tmux on darwin, since nohup
+       // doesn't work correctly there. See issue #5135.
+       if runtime.GOOS == "darwin" && os.Getenv("TMUX") != "" {
+               t.Skip("Skipping nohup test due to running in tmux on darwin")
+       }
+
        // Again, this time with nohup, assuming we can find it.
        _, err := os.Stat("/usr/bin/nohup")
        if err != nil {
@@ -272,3 +279,12 @@ func TestNohup(t *testing.T) {
                }
        }
 }
+
+// Test that SIGCONT works (issue 8953).
+func TestSIGCONT(t *testing.T) {
+       c := make(chan os.Signal, 1)
+       Notify(c, syscall.SIGCONT)
+       defer Stop(c)
+       syscall.Kill(syscall.Getpid(), syscall.SIGCONT)
+       waitSig(t, c, syscall.SIGCONT)
+}
index 1bdf1d7271808b30bbbf06e7aee0448725e94ad1..01b1b14fd19548d1b091c6d1c9eae05f4f31a4a0 100644 (file)
@@ -11,7 +11,7 @@ import (
        "syscall"
 )
 
-// In assembly.
+// Defined by the runtime package.
 func signal_disable(uint32)
 func signal_enable(uint32)
 func signal_ignore(uint32)
index 605c1d9b64f55c9e0f52ad9549c94eb0e99c0ade..69e63230eb304b4294fbd79e88a75cfe8d3b61bd 100644 (file)
@@ -9,21 +9,12 @@ import (
        "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.Mtim),
-               sys:     st,
-       }
-       fs.mode = FileMode(st.Mode & 0777)
-       switch st.Mode & syscall.S_IFMT {
+func fillFileStatFromSys(fs *fileStat, name string) {
+       fs.name = basename(name)
+       fs.size = int64(fs.sys.Size)
+       fs.modTime = timespecToTime(fs.sys.Mtim)
+       fs.mode = FileMode(fs.sys.Mode & 0777)
+       switch fs.sys.Mode & syscall.S_IFMT {
        case syscall.S_IFBLK:
                fs.mode |= ModeDevice
        case syscall.S_IFCHR:
@@ -39,16 +30,15 @@ func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
        case syscall.S_IFSOCK:
                fs.mode |= ModeSocket
        }
-       if st.Mode&syscall.S_ISGID != 0 {
+       if fs.sys.Mode&syscall.S_ISGID != 0 {
                fs.mode |= ModeSetgid
        }
-       if st.Mode&syscall.S_ISUID != 0 {
+       if fs.sys.Mode&syscall.S_ISUID != 0 {
                fs.mode |= ModeSetuid
        }
-       if st.Mode&syscall.S_ISVTX != 0 {
+       if fs.sys.Mode&syscall.S_ISVTX != 0 {
                fs.mode |= ModeSticky
        }
-       return fs
 }
 
 func timespecToTime(ts syscall.Timespec) time.Time {
index 2ffb60fe259c003ed6d81ee6cbc138e8e9108eac..9dc7a99fb7f52dad9bde085f4ebc8884c53237b4 100644 (file)
@@ -9,22 +9,13 @@ import (
        "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.Mtimespec),
-               sys:     st,
-       }
-       fs.mode = FileMode(st.Mode & 0777)
-       switch st.Mode & syscall.S_IFMT {
-       case syscall.S_IFBLK:
+func fillFileStatFromSys(fs *fileStat, name string) {
+       fs.name = basename(name)
+       fs.size = int64(fs.sys.Size)
+       fs.modTime = timespecToTime(fs.sys.Mtimespec)
+       fs.mode = FileMode(fs.sys.Mode & 0777)
+       switch fs.sys.Mode & syscall.S_IFMT {
+       case syscall.S_IFBLK, syscall.S_IFWHT:
                fs.mode |= ModeDevice
        case syscall.S_IFCHR:
                fs.mode |= ModeDevice | ModeCharDevice
@@ -39,16 +30,15 @@ func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
        case syscall.S_IFSOCK:
                fs.mode |= ModeSocket
        }
-       if st.Mode&syscall.S_ISGID != 0 {
+       if fs.sys.Mode&syscall.S_ISGID != 0 {
                fs.mode |= ModeSetgid
        }
-       if st.Mode&syscall.S_ISUID != 0 {
+       if fs.sys.Mode&syscall.S_ISUID != 0 {
                fs.mode |= ModeSetuid
        }
-       if st.Mode&syscall.S_ISVTX != 0 {
+       if fs.sys.Mode&syscall.S_ISVTX != 0 {
                fs.mode |= ModeSticky
        }
-       return fs
 }
 
 func timespecToTime(ts syscall.Timespec) time.Time {
index 605c1d9b64f55c9e0f52ad9549c94eb0e99c0ade..69e63230eb304b4294fbd79e88a75cfe8d3b61bd 100644 (file)
@@ -9,21 +9,12 @@ import (
        "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.Mtim),
-               sys:     st,
-       }
-       fs.mode = FileMode(st.Mode & 0777)
-       switch st.Mode & syscall.S_IFMT {
+func fillFileStatFromSys(fs *fileStat, name string) {
+       fs.name = basename(name)
+       fs.size = int64(fs.sys.Size)
+       fs.modTime = timespecToTime(fs.sys.Mtim)
+       fs.mode = FileMode(fs.sys.Mode & 0777)
+       switch fs.sys.Mode & syscall.S_IFMT {
        case syscall.S_IFBLK:
                fs.mode |= ModeDevice
        case syscall.S_IFCHR:
@@ -39,16 +30,15 @@ func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
        case syscall.S_IFSOCK:
                fs.mode |= ModeSocket
        }
-       if st.Mode&syscall.S_ISGID != 0 {
+       if fs.sys.Mode&syscall.S_ISGID != 0 {
                fs.mode |= ModeSetgid
        }
-       if st.Mode&syscall.S_ISUID != 0 {
+       if fs.sys.Mode&syscall.S_ISUID != 0 {
                fs.mode |= ModeSetuid
        }
-       if st.Mode&syscall.S_ISVTX != 0 {
+       if fs.sys.Mode&syscall.S_ISVTX != 0 {
                fs.mode |= ModeSticky
        }
-       return fs
 }
 
 func timespecToTime(ts syscall.Timespec) time.Time {
index a503b59fa3fd2e461bb12928e95e1af97172cf59..d3bed14e430f68e8dfbd7ac8e3b0c75b265b362b 100644 (file)
@@ -9,21 +9,12 @@ import (
        "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 {
+func fillFileStatFromSys(fs *fileStat, name string) {
+       fs.name = basename(name)
+       fs.size = int64(fs.sys.Size)
+       fs.modTime = timespecToTime(fs.sys.Mtime, fs.sys.MtimeNsec)
+       fs.mode = FileMode(fs.sys.Mode & 0777)
+       switch fs.sys.Mode & syscall.S_IFMT {
        case syscall.S_IFBLK:
                fs.mode |= ModeDevice
        case syscall.S_IFCHR:
@@ -39,16 +30,15 @@ func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
        case syscall.S_IFSOCK:
                fs.mode |= ModeSocket
        }
-       if st.Mode&syscall.S_ISGID != 0 {
+       if fs.sys.Mode&syscall.S_ISGID != 0 {
                fs.mode |= ModeSetgid
        }
-       if st.Mode&syscall.S_ISUID != 0 {
+       if fs.sys.Mode&syscall.S_ISUID != 0 {
                fs.mode |= ModeSetuid
        }
-       if st.Mode&syscall.S_ISVTX != 0 {
+       if fs.sys.Mode&syscall.S_ISVTX != 0 {
                fs.mode |= ModeSticky
        }
-       return fs
 }
 
 func timespecToTime(sec, nsec int64) time.Time {
index 3e88bd829e656a28d20a1d3b6b5f3f1683d28f62..aad429dcb966f9493e3a1eaa73c45837423c2fd5 100644 (file)
@@ -9,21 +9,12 @@ import (
        "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: timestrucToTime(st.Mtim),
-               sys:     st,
-       }
-       fs.mode = FileMode(st.Mode & 0777)
-       switch st.Mode & syscall.S_IFMT {
+func fillFileStatFromSys(fs *fileStat, name string) {
+       fs.name = basename(name)
+       fs.size = int64(fs.sys.Size)
+       fs.modTime = timestrucToTime(fs.sys.Mtim)
+       fs.mode = FileMode(fs.sys.Mode & 0777)
+       switch fs.sys.Mode & syscall.S_IFMT {
        case syscall.S_IFBLK:
                fs.mode |= ModeDevice
        case syscall.S_IFCHR:
@@ -39,16 +30,15 @@ func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
        case syscall.S_IFSOCK:
                fs.mode |= ModeSocket
        }
-       if st.Mode&syscall.S_ISGID != 0 {
+       if fs.sys.Mode&syscall.S_ISGID != 0 {
                fs.mode |= ModeSetgid
        }
-       if st.Mode&syscall.S_ISUID != 0 {
+       if fs.sys.Mode&syscall.S_ISUID != 0 {
                fs.mode |= ModeSetuid
        }
-       if st.Mode&syscall.S_ISVTX != 0 {
+       if fs.sys.Mode&syscall.S_ISVTX != 0 {
                fs.mode |= ModeSticky
        }
-       return fs
 }
 
 func timestrucToTime(ts syscall.Timestruc) time.Time {
similarity index 93%
rename from libgo/go/os/types_notwin.go
rename to libgo/go/os/types_plan9.go
index ea1a07393095fa1c3b3cfd2e9e5be0ed62ceef1c..6d46ca9dd3d52a090d69aaedd60fa0e5951d0026 100644 (file)
@@ -2,13 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !windows
-
 package os
 
-import (
-       "time"
-)
+import "time"
 
 // A fileStat is the implementation of FileInfo returned by Stat and Lstat.
 type fileStat struct {
diff --git a/libgo/go/os/types_unix.go b/libgo/go/os/types_unix.go
new file mode 100644 (file)
index 0000000..056220c
--- /dev/null
@@ -0,0 +1,27 @@
+// 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 !windows
+// +build !plan9
+
+package os
+
+import (
+       "syscall"
+       "time"
+)
+
+// A fileStat is the implementation of FileInfo returned by Stat and Lstat.
+type fileStat struct {
+       name    string
+       size    int64
+       mode    FileMode
+       modTime time.Time
+       sys     syscall.Stat_t
+}
+
+func (fs *fileStat) Size() int64        { return fs.size }
+func (fs *fileStat) Mode() FileMode     { return fs.mode }
+func (fs *fileStat) ModTime() time.Time { return fs.modTime }
+func (fs *fileStat) Sys() interface{}   { return &fs.sys }
index 27d85d15c6c5b6e9a3f41dc7d022029dd618a727..893be1b198817708b7b5bb884bcf5c671ac7a748 100644 (file)
@@ -35,7 +35,7 @@ func ExampleRel() {
        // On Unix:
        // "/a/b/c": "b/c" <nil>
        // "/b/c": "../b/c" <nil>
-       // "./b/c": "" Rel: can't make b/c relative to /a
+       // "./b/c": "" Rel: can't make ./b/c relative to /a
 }
 
 func ExampleSplit() {
index c29f93fb7bbccbec539dc3d054470dcbee53e90c..209c67f30fd2b3eda8b1e850b264da33127e0e8b 100644 (file)
@@ -168,7 +168,7 @@ var globSymlinkTests = []struct {
 
 func TestGlobSymlink(t *testing.T) {
        switch runtime.GOOS {
-       case "nacl", "plan9":
+       case "android", "nacl", "plan9":
                t.Skipf("skipping on %s", runtime.GOOS)
        case "windows":
                if !supportsSymlinks {
index 5dc5cfd49e734eb7c79a82fc219f41db7bbbb0a1..dd6f3e7a994531116300bbaa8efdb36b6c7bfb06 100644 (file)
@@ -258,7 +258,7 @@ func Rel(basepath, targpath string) (string, error) {
        targVol := VolumeName(targpath)
        base := Clean(basepath)
        targ := Clean(targpath)
-       if targ == base {
+       if sameWord(targ, base) {
                return ".", nil
        }
        base = base[len(baseVol):]
@@ -269,8 +269,8 @@ func Rel(basepath, targpath string) (string, error) {
        // Can't use IsAbs - `\a` and `a` are both relative in Windows.
        baseSlashed := len(base) > 0 && base[0] == Separator
        targSlashed := len(targ) > 0 && targ[0] == Separator
-       if baseSlashed != targSlashed || baseVol != targVol {
-               return "", errors.New("Rel: can't make " + targ + " relative to " + base)
+       if baseSlashed != targSlashed || !sameWord(baseVol, targVol) {
+               return "", errors.New("Rel: can't make " + targpath + " relative to " + basepath)
        }
        // Position base[b0:bi] and targ[t0:ti] at the first differing elements.
        bl := len(base)
@@ -283,7 +283,7 @@ func Rel(basepath, targpath string) (string, error) {
                for ti < tl && targ[ti] != Separator {
                        ti++
                }
-               if targ[t0:ti] != base[b0:bi] {
+               if !sameWord(targ[t0:ti], base[b0:bi]) {
                        break
                }
                if bi < bl {
@@ -296,7 +296,7 @@ func Rel(basepath, targpath string) (string, error) {
                t0 = ti
        }
        if base[b0:bi] == ".." {
-               return "", errors.New("Rel: can't make " + targ + " relative to " + base)
+               return "", errors.New("Rel: can't make " + targpath + " relative to " + basepath)
        }
        if b0 != bl {
                // Base elements left. Must go up before going down.
index 962774efd5d9aa180662d31d95f7df8cd444f15c..60d46d9d421d21efb821a06afbffbb14c26bc343 100644 (file)
@@ -42,3 +42,7 @@ func join(elem []string) string {
        }
        return ""
 }
+
+func sameWord(a, b string) bool {
+       return a == b
+}
index b2536cb77a40c4d5011d8fce4b26782a5840f9bf..10ea795e90eb569279b55f2ba4c05bf986af7f97 100644 (file)
@@ -270,7 +270,12 @@ var winjointests = []JoinTest{
        {[]string{`C:\Windows\`, `System32`}, `C:\Windows\System32`},
        {[]string{`C:\Windows\`, ``}, `C:\Windows`},
        {[]string{`C:\`, `Windows`}, `C:\Windows`},
-       {[]string{`C:`, `Windows`}, `C:\Windows`},
+       {[]string{`C:`, `a`}, `C:a`},
+       {[]string{`C:`, `a\b`}, `C:a\b`},
+       {[]string{`C:`, `a`, `b`}, `C:a\b`},
+       {[]string{`C:.`, `a`}, `C:a`},
+       {[]string{`C:a`, `b`}, `C:a\b`},
+       {[]string{`C:a`, `b`, `d`}, `C:a\b\d`},
        {[]string{`\\host\share`, `foo`}, `\\host\share\foo`},
        {[]string{`\\host\share\foo`}, `\\host\share\foo`},
        {[]string{`//host/share`, `foo/bar`}, `\\host\share\foo\bar`},
@@ -405,18 +410,18 @@ func mark(path string, info os.FileInfo, err error, errors *[]error, clear bool)
 func chtmpdir(t *testing.T) (restore func()) {
        oldwd, err := os.Getwd()
        if err != nil {
-               t.Fatal("chtmpdir: %v", err)
+               t.Fatalf("chtmpdir: %v", err)
        }
        d, err := ioutil.TempDir("", "test")
        if err != nil {
-               t.Fatal("chtmpdir: %v", err)
+               t.Fatalf("chtmpdir: %v", err)
        }
        if err := os.Chdir(d); err != nil {
-               t.Fatal("chtmpdir: %v", err)
+               t.Fatalf("chtmpdir: %v", err)
        }
        return func() {
                if err := os.Chdir(oldwd); err != nil {
-                       t.Fatal("chtmpdir: %v", err)
+                       t.Fatalf("chtmpdir: %v", err)
                }
                os.RemoveAll(d)
        }
@@ -755,8 +760,16 @@ var EvalSymlinksTests = []EvalSymlinksTest{
        {"test/linkabs", "/"},
 }
 
-var EvalSymlinksAbsWindowsTests = []EvalSymlinksTest{
-       {`c:\`, `c:\`},
+// findEvalSymlinksTestDirsDest searches testDirs
+// for matching path and returns correspondent dest.
+func findEvalSymlinksTestDirsDest(t *testing.T, testDirs []EvalSymlinksTest, path string) string {
+       for _, d := range testDirs {
+               if d.path == path {
+                       return d.dest
+               }
+       }
+       t.Fatalf("did not find %q in testDirs slice", path)
+       return ""
 }
 
 // simpleJoin builds a file name from the directory and path.
@@ -767,9 +780,12 @@ func simpleJoin(dir, path string) string {
 
 func TestEvalSymlinks(t *testing.T) {
        switch runtime.GOOS {
-       case "nacl", "plan9":
+       case "android", "nacl", "plan9":
                t.Skipf("skipping on %s", runtime.GOOS)
        }
+       if !supportsSymlinks {
+               t.Skip("skipping because symlinks are not supported")
+       }
 
        tmpDir, err := ioutil.TempDir("", "evalsymlink")
        if err != nil {
@@ -784,38 +800,37 @@ func TestEvalSymlinks(t *testing.T) {
                t.Fatal("eval symlink for tmp dir:", err)
        }
 
+       tests := EvalSymlinksTests
+       testdirs := EvalSymlinksTestDirs
+       if runtime.GOOS == "windows" {
+               if len(tmpDir) < 3 {
+                       t.Fatalf("tmpDir path %q is too short", tmpDir)
+               }
+               if tmpDir[1] != ':' {
+                       t.Fatalf("tmpDir path %q must have drive letter in it", tmpDir)
+               }
+               newtest := EvalSymlinksTest{"test/linkabswin", tmpDir[:3]}
+               tests = append(tests, newtest)
+               testdirs = append(testdirs, newtest)
+       }
+
        // Create the symlink farm using relative paths.
-       for _, d := range EvalSymlinksTestDirs {
+       for _, d := range testdirs {
                var err error
                path := simpleJoin(tmpDir, d.path)
                if d.dest == "" {
                        err = os.Mkdir(path, 0755)
                } else {
-                       if supportsSymlinks {
-                               err = os.Symlink(d.dest, path)
-                       }
+                       err = os.Symlink(d.dest, path)
                }
                if err != nil {
                        t.Fatal(err)
                }
        }
 
-       var tests []EvalSymlinksTest
-       if supportsSymlinks {
-               tests = EvalSymlinksTests
-       } else {
-               for _, d := range EvalSymlinksTests {
-                       if d.path == d.dest {
-                               // will test only real files and directories
-                               tests = append(tests, d)
-                               // test "canonical" names
-                               d2 := EvalSymlinksTest{
-                                       path: strings.ToUpper(d.path),
-                                       dest: d.dest,
-                               }
-                               tests = append(tests, d2)
-                       }
-               }
+       wd, err := os.Getwd()
+       if err != nil {
+               t.Fatal(err)
        }
 
        // Evaluate the symlink farm.
@@ -830,6 +845,125 @@ func TestEvalSymlinks(t *testing.T) {
                } else if filepath.Clean(p) != filepath.Clean(dest) {
                        t.Errorf("Clean(%q)=%q, want %q", path, p, dest)
                }
+
+               // test EvalSymlinks(".")
+               func() {
+                       defer func() {
+                               err := os.Chdir(wd)
+                               if err != nil {
+                                       t.Fatal(err)
+                               }
+                       }()
+
+                       err := os.Chdir(path)
+                       if err != nil {
+                               t.Error(err)
+                               return
+                       }
+                       p, err := filepath.EvalSymlinks(".")
+                       if err != nil {
+                               t.Errorf(`EvalSymlinks(".") in %q directory error: %v`, d.path, err)
+                               return
+                       }
+                       if p == "." {
+                               return
+                       }
+                       want := filepath.Clean(findEvalSymlinksTestDirsDest(t, testdirs, d.path))
+                       if p == want {
+                               return
+                       }
+                       t.Errorf(`EvalSymlinks(".") in %q directory returns %q, want "." or %q`, d.path, p, want)
+               }()
+
+               // test EvalSymlinks where parameter is relative path
+               func() {
+                       defer func() {
+                               err := os.Chdir(wd)
+                               if err != nil {
+                                       t.Fatal(err)
+                               }
+                       }()
+
+                       err := os.Chdir(tmpDir)
+                       if err != nil {
+                               t.Error(err)
+                               return
+                       }
+                       if p, err := filepath.EvalSymlinks(d.path); err != nil {
+                               t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
+                       } else if filepath.Clean(p) != filepath.Clean(d.dest) {
+                               t.Errorf("Clean(%q)=%q, want %q", d.path, p, d.dest)
+                       }
+               }()
+       }
+}
+
+func TestIssue13582(t *testing.T) {
+       switch runtime.GOOS {
+       case "android", "nacl", "plan9":
+               t.Skipf("skipping on %s", runtime.GOOS)
+       }
+       if !supportsSymlinks {
+               t.Skip("skipping because symlinks are not supported")
+       }
+
+       tmpDir, err := ioutil.TempDir("", "issue13582")
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer os.RemoveAll(tmpDir)
+
+       dir := filepath.Join(tmpDir, "dir")
+       err = os.Mkdir(dir, 0755)
+       if err != nil {
+               t.Fatal(err)
+       }
+       linkToDir := filepath.Join(tmpDir, "link_to_dir")
+       err = os.Symlink(dir, linkToDir)
+       if err != nil {
+               t.Fatal(err)
+       }
+       file := filepath.Join(linkToDir, "file")
+       err = ioutil.WriteFile(file, nil, 0644)
+       if err != nil {
+               t.Fatal(err)
+       }
+       link1 := filepath.Join(linkToDir, "link1")
+       err = os.Symlink(file, link1)
+       if err != nil {
+               t.Fatal(err)
+       }
+       link2 := filepath.Join(linkToDir, "link2")
+       err = os.Symlink(link1, link2)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       // /tmp may itself be a symlink!
+       realTmpDir, err := filepath.EvalSymlinks(tmpDir)
+       if err != nil {
+               t.Fatal(err)
+       }
+       realDir := filepath.Join(realTmpDir, "dir")
+       realFile := filepath.Join(realDir, "file")
+
+       tests := []struct {
+               path, want string
+       }{
+               {dir, realDir},
+               {linkToDir, realDir},
+               {file, realFile},
+               {link1, realFile},
+               {link2, realFile},
+       }
+       for i, test := range tests {
+               have, err := filepath.EvalSymlinks(test.path)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               if have != test.want {
+                       t.Errorf("test#%d: EvalSymlinks(%q) returns %q, want %q", i, test.path, have, test.want)
+               }
        }
 }
 
@@ -976,6 +1110,9 @@ var winreltests = []RelTests{
        {`C:a\b\c`, `C:a/b/d`, `..\d`},
        {`C:\`, `D:\`, `err`},
        {`C:`, `D:`, `err`},
+       {`C:\Projects`, `c:\projects\src`, `src`},
+       {`C:\Projects`, `c:\projects`, `.`},
+       {`C:\Projects\a\..`, `c:\projects`, `.`},
 }
 
 func TestRel(t *testing.T) {
index d241d78fa781cfba06253ba4bd196243e1251dd4..2d242cc0b5d798320cbad85599953188e9d82be6 100644 (file)
@@ -44,3 +44,7 @@ func join(elem []string) string {
        }
        return ""
 }
+
+func sameWord(a, b string) bool {
+       return a == b
+}
index bcfe0a34b0a181b2118c070d771109c12baeae8b..ef6e7ca93f4adaaed37d334cd1d6e90ef628ef05 100644 (file)
@@ -120,6 +120,11 @@ func join(elem []string) string {
 
 // joinNonEmpty is like join, but it assumes that the first element is non-empty.
 func joinNonEmpty(elem []string) string {
+       if len(elem[0]) == 2 && elem[0][1] == ':' {
+               // First element is drive leter without terminating slash.
+               // Keep path relative to current directory on that drive.
+               return Clean(elem[0] + strings.Join(elem[1:], string(Separator)))
+       }
        // The following logic prevents Join from inadvertently creating a
        // UNC path on Windows. Unless the first element is a UNC path, Join
        // shouldn't create a UNC path. See golang.org/issue/9167.
@@ -145,3 +150,7 @@ func joinNonEmpty(elem []string) string {
 func isUNC(path string) bool {
        return volumeNameLen(path) > 2
 }
+
+func sameWord(a, b string) bool {
+       return strings.EqualFold(a, b)
+}
index df0a9e0c2ba9988f7bffc38e2dc2df6e81417c0c..bc287c5ecb36a239951325d4dada452d3099b513 100644 (file)
 package filepath
 
 import (
-       "bytes"
        "errors"
        "os"
+       "runtime"
 )
 
-const utf8RuneSelf = 0x80
+// isRoot returns true if path is root of file system
+// (`/` on unix and `/`, `\`, `c:\` or `c:/` on windows).
+func isRoot(path string) bool {
+       if runtime.GOOS != "windows" {
+               return path == "/"
+       }
+       switch len(path) {
+       case 1:
+               return os.IsPathSeparator(path[0])
+       case 3:
+               return path[1] == ':' && os.IsPathSeparator(path[2])
+       }
+       return false
+}
 
-func walkSymlinks(path string) (string, error) {
-       const maxIter = 255
-       originalPath := path
-       // consume path by taking each frontmost path element,
-       // expanding it if it's a symlink, and appending it to b
-       var b bytes.Buffer
-       for n := 0; path != ""; n++ {
-               if n > maxIter {
-                       return "", errors.New("EvalSymlinks: too many links in " + originalPath)
-               }
+// isDriveLetter returns true if path is Windows drive letter (like "c:").
+func isDriveLetter(path string) bool {
+       if runtime.GOOS != "windows" {
+               return false
+       }
+       return len(path) == 2 && path[1] == ':'
+}
 
-               // find next path component, p
-               var i = -1
-               for j, c := range path {
-                       if c < utf8RuneSelf && os.IsPathSeparator(uint8(c)) {
-                               i = j
-                               break
-                       }
-               }
-               var p string
-               if i == -1 {
-                       p, path = path, ""
-               } else {
-                       p, path = path[:i], path[i+1:]
-               }
+func walkLink(path string, linksWalked *int) (newpath string, islink bool, err error) {
+       if *linksWalked > 255 {
+               return "", false, errors.New("EvalSymlinks: too many links")
+       }
+       fi, err := os.Lstat(path)
+       if err != nil {
+               return "", false, err
+       }
+       if fi.Mode()&os.ModeSymlink == 0 {
+               return path, false, nil
+       }
+       newpath, err = os.Readlink(path)
+       if err != nil {
+               return "", false, err
+       }
+       *linksWalked++
+       return newpath, true, nil
+}
 
-               if p == "" {
-                       if b.Len() == 0 {
-                               // must be absolute path
-                               b.WriteRune(Separator)
+func walkLinks(path string, linksWalked *int) (string, error) {
+       switch dir, file := Split(path); {
+       case dir == "":
+               newpath, _, err := walkLink(file, linksWalked)
+               return newpath, err
+       case file == "":
+               if isDriveLetter(dir) {
+                       return dir, nil
+               }
+               if os.IsPathSeparator(dir[len(dir)-1]) {
+                       if isRoot(dir) {
+                               return dir, nil
                        }
-                       continue
+                       return walkLinks(dir[:len(dir)-1], linksWalked)
                }
-
-               fi, err := os.Lstat(b.String() + p)
+               newpath, _, err := walkLink(dir, linksWalked)
+               return newpath, err
+       default:
+               newdir, err := walkLinks(dir, linksWalked)
                if err != nil {
                        return "", err
                }
-               if fi.Mode()&os.ModeSymlink == 0 {
-                       b.WriteString(p)
-                       if path != "" || (b.Len() == 2 && len(p) == 2 && p[1] == ':') {
-                               b.WriteRune(Separator)
-                       }
-                       continue
+               newpath, islink, err := walkLink(Join(newdir, file), linksWalked)
+               if err != nil {
+                       return "", err
+               }
+               if !islink {
+                       return newpath, nil
                }
+               if IsAbs(newpath) || os.IsPathSeparator(newpath[0]) {
+                       return newpath, nil
+               }
+               return Join(newdir, newpath), nil
+       }
+}
 
-               // it's a symlink, put it at the front of path
-               dest, err := os.Readlink(b.String() + p)
+func walkSymlinks(path string) (string, error) {
+       if path == "" {
+               return path, nil
+       }
+       var linksWalked int // to protect against cycles
+       for {
+               i := linksWalked
+               newpath, err := walkLinks(path, &linksWalked)
                if err != nil {
                        return "", err
                }
-               if IsAbs(dest) || os.IsPathSeparator(dest[0]) {
-                       b.Reset()
+               if runtime.GOOS == "windows" {
+                       // walkLinks(".", ...) always retuns "." on unix.
+                       // But on windows it returns symlink target, if current
+                       // directory is a symlink. Stop the walk, if symlink
+                       // target is not absolute path, and return "."
+                       // to the caller (just like unix does).
+                       if path == "." && !IsAbs(newpath) {
+                               return ".", nil
+                       }
+               }
+               if i == linksWalked {
+                       return Clean(newpath), nil
                }
-               path = dest + string(Separator) + path
+               path = newpath
        }
-       return Clean(b.String()), nil
 }
index 4b38f6fac3f33002ae1f06188316661c30affbc1..eb48367ec2bc4a9ce93c9d2ea77b0e224f61c239 100644 (file)
@@ -51,7 +51,6 @@ func evalSymlinks(path string) (string, error) {
        if err != nil {
                return "", err
        }
-
        p, err := toShort(path)
        if err != nil {
                return "", err
index 77f2185eaecb0d68618c5d5d7f18bc4e6e61e77d..01071a9a826b393ad4c8dc241b6c1ebc8bfd0f99 100644 (file)
@@ -136,7 +136,7 @@ func Clean(path string) string {
 
 // Split splits path immediately following the final slash,
 // separating it into a directory and file name component.
-// If there is no slash path, Split returns an empty dir and
+// If there is no slash in path, Split returns an empty dir and
 // file set to path.
 // The returned values have the property that path = dir+file.
 func Split(path string) (dir, file string) {
index 33ee9ed83cc12d98cc5f5c08262bd14c2f2ede2e..595d6908f7d9a0457edb9eb351fc1febfa0c47fc 100644 (file)
@@ -10,6 +10,7 @@ import (
        "flag"
        "fmt"
        "io"
+       "math"
        "math/rand"
        "os"
        . "reflect"
@@ -647,6 +648,8 @@ var (
        fn3 = func() { fn1() } // Not nil.
 )
 
+type self struct{}
+
 var deepEqualTests = []DeepEqualTest{
        // Equalities
        {nil, nil, true},
@@ -681,6 +684,13 @@ var deepEqualTests = []DeepEqualTest{
        {fn1, fn3, false},
        {fn3, fn3, false},
        {[][]int{{1}}, [][]int{{2}}, false},
+       {math.NaN(), math.NaN(), false},
+       {&[1]float64{math.NaN()}, &[1]float64{math.NaN()}, false},
+       {&[1]float64{math.NaN()}, self{}, true},
+       {[]float64{math.NaN()}, []float64{math.NaN()}, false},
+       {[]float64{math.NaN()}, self{}, true},
+       {map[float64]float64{math.NaN(): 1}, map[float64]float64{1: 2}, false},
+       {map[float64]float64{math.NaN(): 1}, self{}, true},
 
        // Nil vs empty: not the same.
        {[]int{}, []int(nil), false},
@@ -702,6 +712,9 @@ var deepEqualTests = []DeepEqualTest{
 
 func TestDeepEqual(t *testing.T) {
        for _, test := range deepEqualTests {
+               if test.b == (self{}) {
+                       test.b = test.a
+               }
                if r := DeepEqual(test.a, test.b); r != test.eq {
                        t.Errorf("DeepEqual(%v, %v) = %v, want %v", test.a, test.b, r, test.eq)
                }
@@ -2783,14 +2796,27 @@ func TestSetBytes(t *testing.T) {
 type Private struct {
        x int
        y **int
+       Z int
 }
 
 func (p *Private) m() {
 }
 
+type private struct {
+       Z int
+       z int
+       S string
+       A [1]Private
+       T []Private
+}
+
+func (p *private) P() {
+}
+
 type Public struct {
        X int
        Y **int
+       private
 }
 
 func (p *Public) M() {
@@ -2798,17 +2824,30 @@ func (p *Public) M() {
 
 func TestUnexported(t *testing.T) {
        var pub Public
+       pub.S = "S"
+       pub.T = pub.A[:]
        v := ValueOf(&pub)
        isValid(v.Elem().Field(0))
        isValid(v.Elem().Field(1))
+       isValid(v.Elem().Field(2))
        isValid(v.Elem().FieldByName("X"))
        isValid(v.Elem().FieldByName("Y"))
+       isValid(v.Elem().FieldByName("Z"))
        isValid(v.Type().Method(0).Func)
+       m, _ := v.Type().MethodByName("M")
+       isValid(m.Func)
+       m, _ = v.Type().MethodByName("P")
+       isValid(m.Func)
        isNonNil(v.Elem().Field(0).Interface())
        isNonNil(v.Elem().Field(1).Interface())
+       isNonNil(v.Elem().Field(2).Field(2).Index(0))
        isNonNil(v.Elem().FieldByName("X").Interface())
        isNonNil(v.Elem().FieldByName("Y").Interface())
+       isNonNil(v.Elem().FieldByName("Z").Interface())
+       isNonNil(v.Elem().FieldByName("S").Index(0).Interface())
        isNonNil(v.Type().Method(0).Func.Interface())
+       m, _ = v.Type().MethodByName("P")
+       isNonNil(m.Func.Interface())
 
        var priv Private
        v = ValueOf(&priv)
@@ -2824,6 +2863,170 @@ func TestUnexported(t *testing.T) {
        shouldPanic(func() { v.Type().Method(0).Func.Interface() })
 }
 
+func TestSetPanic(t *testing.T) {
+       ok := func(f func()) { f() }
+       bad := shouldPanic
+       clear := func(v Value) { v.Set(Zero(v.Type())) }
+
+       type t0 struct {
+               W int
+       }
+
+       type t1 struct {
+               Y int
+               t0
+       }
+
+       type T2 struct {
+               Z       int
+               namedT0 t0
+       }
+
+       type T struct {
+               X int
+               t1
+               T2
+               NamedT1 t1
+               NamedT2 T2
+               namedT1 t1
+               namedT2 T2
+       }
+
+       // not addressable
+       v := ValueOf(T{})
+       bad(func() { clear(v.Field(0)) })                   // .X
+       bad(func() { clear(v.Field(1)) })                   // .t1
+       bad(func() { clear(v.Field(1).Field(0)) })          // .t1.Y
+       bad(func() { clear(v.Field(1).Field(1)) })          // .t1.t0
+       bad(func() { clear(v.Field(1).Field(1).Field(0)) }) // .t1.t0.W
+       bad(func() { clear(v.Field(2)) })                   // .T2
+       bad(func() { clear(v.Field(2).Field(0)) })          // .T2.Z
+       bad(func() { clear(v.Field(2).Field(1)) })          // .T2.namedT0
+       bad(func() { clear(v.Field(2).Field(1).Field(0)) }) // .T2.namedT0.W
+       bad(func() { clear(v.Field(3)) })                   // .NamedT1
+       bad(func() { clear(v.Field(3).Field(0)) })          // .NamedT1.Y
+       bad(func() { clear(v.Field(3).Field(1)) })          // .NamedT1.t0
+       bad(func() { clear(v.Field(3).Field(1).Field(0)) }) // .NamedT1.t0.W
+       bad(func() { clear(v.Field(4)) })                   // .NamedT2
+       bad(func() { clear(v.Field(4).Field(0)) })          // .NamedT2.Z
+       bad(func() { clear(v.Field(4).Field(1)) })          // .NamedT2.namedT0
+       bad(func() { clear(v.Field(4).Field(1).Field(0)) }) // .NamedT2.namedT0.W
+       bad(func() { clear(v.Field(5)) })                   // .namedT1
+       bad(func() { clear(v.Field(5).Field(0)) })          // .namedT1.Y
+       bad(func() { clear(v.Field(5).Field(1)) })          // .namedT1.t0
+       bad(func() { clear(v.Field(5).Field(1).Field(0)) }) // .namedT1.t0.W
+       bad(func() { clear(v.Field(6)) })                   // .namedT2
+       bad(func() { clear(v.Field(6).Field(0)) })          // .namedT2.Z
+       bad(func() { clear(v.Field(6).Field(1)) })          // .namedT2.namedT0
+       bad(func() { clear(v.Field(6).Field(1).Field(0)) }) // .namedT2.namedT0.W
+
+       // addressable
+       v = ValueOf(&T{}).Elem()
+       ok(func() { clear(v.Field(0)) })                    // .X
+       bad(func() { clear(v.Field(1)) })                   // .t1
+       ok(func() { clear(v.Field(1).Field(0)) })           // .t1.Y
+       bad(func() { clear(v.Field(1).Field(1)) })          // .t1.t0
+       ok(func() { clear(v.Field(1).Field(1).Field(0)) })  // .t1.t0.W
+       ok(func() { clear(v.Field(2)) })                    // .T2
+       ok(func() { clear(v.Field(2).Field(0)) })           // .T2.Z
+       bad(func() { clear(v.Field(2).Field(1)) })          // .T2.namedT0
+       bad(func() { clear(v.Field(2).Field(1).Field(0)) }) // .T2.namedT0.W
+       ok(func() { clear(v.Field(3)) })                    // .NamedT1
+       ok(func() { clear(v.Field(3).Field(0)) })           // .NamedT1.Y
+       bad(func() { clear(v.Field(3).Field(1)) })          // .NamedT1.t0
+       ok(func() { clear(v.Field(3).Field(1).Field(0)) })  // .NamedT1.t0.W
+       ok(func() { clear(v.Field(4)) })                    // .NamedT2
+       ok(func() { clear(v.Field(4).Field(0)) })           // .NamedT2.Z
+       bad(func() { clear(v.Field(4).Field(1)) })          // .NamedT2.namedT0
+       bad(func() { clear(v.Field(4).Field(1).Field(0)) }) // .NamedT2.namedT0.W
+       bad(func() { clear(v.Field(5)) })                   // .namedT1
+       bad(func() { clear(v.Field(5).Field(0)) })          // .namedT1.Y
+       bad(func() { clear(v.Field(5).Field(1)) })          // .namedT1.t0
+       bad(func() { clear(v.Field(5).Field(1).Field(0)) }) // .namedT1.t0.W
+       bad(func() { clear(v.Field(6)) })                   // .namedT2
+       bad(func() { clear(v.Field(6).Field(0)) })          // .namedT2.Z
+       bad(func() { clear(v.Field(6).Field(1)) })          // .namedT2.namedT0
+       bad(func() { clear(v.Field(6).Field(1).Field(0)) }) // .namedT2.namedT0.W
+}
+
+type timp int
+
+func (t timp) W() {}
+func (t timp) Y() {}
+func (t timp) w() {}
+func (t timp) y() {}
+
+func TestCallPanic(t *testing.T) {
+       type t0 interface {
+               W()
+               w()
+       }
+       type T1 interface {
+               Y()
+               y()
+       }
+       type T2 struct {
+               T1
+               t0
+       }
+       type T struct {
+               t0 // 0
+               T1 // 1
+
+               NamedT0 t0 // 2
+               NamedT1 T1 // 3
+               NamedT2 T2 // 4
+
+               namedT0 t0 // 5
+               namedT1 T1 // 6
+               namedT2 T2 // 7
+       }
+       ok := func(f func()) { f() }
+       bad := shouldPanic
+       call := func(v Value) { v.Call(nil) }
+
+       i := timp(0)
+       v := ValueOf(T{i, i, i, i, T2{i, i}, i, i, T2{i, i}})
+       ok(func() { call(v.Field(0).Method(0)) })         // .t0.W
+       ok(func() { call(v.Field(0).Elem().Method(0)) })  // .t0.W
+       bad(func() { call(v.Field(0).Method(1)) })        // .t0.w
+       bad(func() { call(v.Field(0).Elem().Method(2)) }) // .t0.w
+       ok(func() { call(v.Field(1).Method(0)) })         // .T1.Y
+       ok(func() { call(v.Field(1).Elem().Method(0)) })  // .T1.Y
+       bad(func() { call(v.Field(1).Method(1)) })        // .T1.y
+       bad(func() { call(v.Field(1).Elem().Method(2)) }) // .T1.y
+
+       ok(func() { call(v.Field(2).Method(0)) })         // .NamedT0.W
+       ok(func() { call(v.Field(2).Elem().Method(0)) })  // .NamedT0.W
+       bad(func() { call(v.Field(2).Method(1)) })        // .NamedT0.w
+       bad(func() { call(v.Field(2).Elem().Method(2)) }) // .NamedT0.w
+
+       ok(func() { call(v.Field(3).Method(0)) })         // .NamedT1.Y
+       ok(func() { call(v.Field(3).Elem().Method(0)) })  // .NamedT1.Y
+       bad(func() { call(v.Field(3).Method(1)) })        // .NamedT1.y
+       bad(func() { call(v.Field(3).Elem().Method(3)) }) // .NamedT1.y
+
+       ok(func() { call(v.Field(4).Field(0).Method(0)) })        // .NamedT2.T1.Y
+       ok(func() { call(v.Field(4).Field(0).Elem().Method(0)) }) // .NamedT2.T1.W
+       ok(func() { call(v.Field(4).Field(1).Method(0)) })        // .NamedT2.t0.W
+       ok(func() { call(v.Field(4).Field(1).Elem().Method(0)) }) // .NamedT2.t0.W
+
+       bad(func() { call(v.Field(5).Method(0)) })        // .namedT0.W
+       bad(func() { call(v.Field(5).Elem().Method(0)) }) // .namedT0.W
+       bad(func() { call(v.Field(5).Method(1)) })        // .namedT0.w
+       bad(func() { call(v.Field(5).Elem().Method(2)) }) // .namedT0.w
+
+       bad(func() { call(v.Field(6).Method(0)) })        // .namedT1.Y
+       bad(func() { call(v.Field(6).Elem().Method(0)) }) // .namedT1.Y
+       bad(func() { call(v.Field(6).Method(0)) })        // .namedT1.y
+       bad(func() { call(v.Field(6).Elem().Method(0)) }) // .namedT1.y
+
+       bad(func() { call(v.Field(7).Field(0).Method(0)) })        // .namedT2.T1.Y
+       bad(func() { call(v.Field(7).Field(0).Elem().Method(0)) }) // .namedT2.T1.W
+       bad(func() { call(v.Field(7).Field(1).Method(0)) })        // .namedT2.t0.W
+       bad(func() { call(v.Field(7).Field(1).Elem().Method(0)) }) // .namedT2.t0.W
+}
+
 func shouldPanic(f func()) {
        defer func() {
                if recover() == nil {
@@ -4786,3 +4989,38 @@ func TestPtrToMethods(t *testing.T) {
                t.Fatal("does not implement Stringer, but should")
        }
 }
+
+func TestMapAlloc(t *testing.T) {
+       if runtime.Compiler == "gccgo" {
+               t.Skip("skipping on gccgo until we have escape analysis")
+       }
+       m := ValueOf(make(map[int]int, 10))
+       k := ValueOf(5)
+       v := ValueOf(7)
+       allocs := testing.AllocsPerRun(100, func() {
+               m.SetMapIndex(k, v)
+       })
+       if allocs > 0.5 {
+               t.Errorf("allocs per map assignment: want 0 got %f", allocs)
+       }
+}
+
+func TestChanAlloc(t *testing.T) {
+       if runtime.Compiler == "gccgo" {
+               t.Skip("skipping on gccgo until we have escape analysis")
+       }
+       // Note: for a chan int, the return Value must be allocated, so we
+       // use a chan *int instead.
+       c := ValueOf(make(chan *int, 1))
+       v := ValueOf(new(int))
+       allocs := testing.AllocsPerRun(100, func() {
+               c.Send(v)
+               _, _ = c.Recv()
+       })
+       if allocs < 0.5 || allocs > 1.5 {
+               t.Errorf("allocs per chan send/recv: want 1 got %f", allocs)
+       }
+       // Note: there is one allocation in reflect.recv which seems to be
+       // a limitation of escape analysis.  If that is ever fixed the
+       // allocs < 0.5 condition will trigger and this test should be fixed.
+}
index f63715c9afc9862681422180aa4ba08b078215c2..3743e8042d3e5f74d38aa5970f86a9971ed4c100 100644 (file)
@@ -6,13 +6,15 @@
 
 package reflect
 
+import "unsafe"
+
 // During deepValueEqual, must keep track of checks that are
 // in progress.  The comparison algorithm assumes that all
 // checks in progress are true when it reencounters them.
 // Visited comparisons are stored in a map indexed by visit.
 type visit struct {
-       a1  uintptr
-       a2  uintptr
+       a1  unsafe.Pointer
+       a2  unsafe.Pointer
        typ Type
 }
 
@@ -37,19 +39,15 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
        }
 
        if v1.CanAddr() && v2.CanAddr() && hard(v1.Kind()) {
-               addr1 := v1.UnsafeAddr()
-               addr2 := v2.UnsafeAddr()
-               if addr1 > addr2 {
+               addr1 := unsafe.Pointer(v1.UnsafeAddr())
+               addr2 := unsafe.Pointer(v2.UnsafeAddr())
+               if uintptr(addr1) > uintptr(addr2) {
                        // Canonicalize order to reduce number of entries in visited.
+                       // Assumes non-moving garbage collector.
                        addr1, addr2 = addr2, addr1
                }
 
-               // Short circuit if references are identical ...
-               if addr1 == addr2 {
-                       return true
-               }
-
-               // ... or already seen
+               // Short circuit if references are already seen.
                typ := v1.Type()
                v := visit{addr1, addr2, typ}
                if visited[v] {
@@ -90,6 +88,9 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
                }
                return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1)
        case Ptr:
+               if v1.Pointer() == v2.Pointer() {
+                       return true
+               }
                return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1)
        case Struct:
                for i, n := 0, v1.NumField(); i < n; i++ {
@@ -109,7 +110,9 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
                        return true
                }
                for _, k := range v1.MapKeys() {
-                       if !deepValueEqual(v1.MapIndex(k), v2.MapIndex(k), visited, depth+1) {
+                       val1 := v1.MapIndex(k)
+                       val2 := v2.MapIndex(k)
+                       if !val1.IsValid() || !val2.IsValid() || !deepValueEqual(v1.MapIndex(k), v2.MapIndex(k), visited, depth+1) {
                                return false
                        }
                }
@@ -126,18 +129,56 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
        }
 }
 
-// DeepEqual tests for deep equality. It uses normal == equality where
-// possible but will scan elements of arrays, slices, maps, and fields of
-// structs. In maps, keys are compared with == but elements use deep
-// equality. DeepEqual correctly handles recursive types. Functions are equal
-// only if they are both nil.
-// An empty slice is not equal to a nil slice.
-func DeepEqual(a1, a2 interface{}) bool {
-       if a1 == nil || a2 == nil {
-               return a1 == a2
+// DeepEqual reports whether x and y are ``deeply equal,'' defined as follows.
+// Two values of identical type are deeply equal if one of the following cases applies.
+// Values of distinct types are never deeply equal.
+//
+// Array values are deeply equal when their corresponding elements are deeply equal.
+//
+// Struct values are deeply equal if their corresponding fields,
+// both exported and unexported, are deeply equal.
+//
+// Func values are deeply equal if both are nil; otherwise they are not deeply equal.
+//
+// Interface values are deeply equal if they hold deeply equal concrete values.
+//
+// Map values are deeply equal if they are the same map object
+// or if they have the same length and their corresponding keys
+// (matched using Go equality) map to deeply equal values.
+//
+// Pointer values are deeply equal if they are equal using Go's == operator
+// or if they point to deeply equal values.
+//
+// Slice values are deeply equal when all of the following are true:
+// they are both nil or both non-nil, they have the same length,
+// and either they point to the same initial entry of the same underlying array
+// (that is, &x[0] == &y[0]) or their corresponding elements (up to length) are deeply equal.
+// Note that a non-nil empty slice and a nil slice (for example, []byte{} and []byte(nil))
+// are not deeply equal.
+//
+// Other values - numbers, bools, strings, and channels - are deeply equal
+// if they are equal using Go's == operator.
+//
+// In general DeepEqual is a recursive relaxation of Go's == operator.
+// However, this idea is impossible to implement without some inconsistency.
+// Specifically, it is possible for a value to be unequal to itself,
+// either because it is of func type (uncomparable in general)
+// or because it is a floating-point NaN value (not equal to itself in floating-point comparison),
+// or because it is an array, struct, or interface containing
+// such a value.
+// On the other hand, pointer values are always equal to themselves,
+// even if they point at or contain such problematic values,
+// because they compare equal using Go's == operator, and that
+// is a sufficient condition to be deeply equal, regardless of content.
+// DeepEqual has been defined so that the same short-cut applies
+// to slices and maps: if x and y are the same slice or the same map,
+// they are deeply equal regardless of content.
+func DeepEqual(x, y interface{}) bool {
+       if x == nil || y == nil {
+               return x == y
        }
-       v1 := ValueOf(a1)
-       v2 := ValueOf(a2)
+       v1 := ValueOf(x)
+       v2 := ValueOf(y)
        if v1.Type() != v2.Type() {
                return false
        }
index 180a364de35e48b25d884d92d75d975777109d12..88da632584c7c9d5256d6eaca7cf99dbaa7ca0c6 100644 (file)
@@ -756,10 +756,10 @@ func (t *interfaceType) MethodByName(name string) (m Method, ok bool) {
 // A StructField describes a single field in a struct.
 type StructField struct {
        // Name is the field name.
+       Name string
        // PkgPath is the package path that qualifies a lower case (unexported)
        // field name.  It is empty for upper case (exported) field names.
        // See https://golang.org/ref/spec#Uniqueness_of_identifiers
-       Name    string
        PkgPath string
 
        Type      Type      // field type
@@ -1733,6 +1733,33 @@ func isReflexive(t *rtype) bool {
        }
 }
 
+// needKeyUpdate reports whether map overwrites require the key to be copied.
+func needKeyUpdate(t *rtype) bool {
+       switch t.Kind() {
+       case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Ptr, UnsafePointer:
+               return false
+       case Float32, Float64, Complex64, Complex128, Interface, String:
+               // Float keys can be updated from +0 to -0.
+               // String keys can be updated to use a smaller backing store.
+               // Interfaces might have floats of strings in them.
+               return true
+       case Array:
+               tt := (*arrayType)(unsafe.Pointer(t))
+               return needKeyUpdate(tt.elem)
+       case Struct:
+               tt := (*structType)(unsafe.Pointer(t))
+               for _, f := range tt.fields {
+                       if needKeyUpdate(f.typ) {
+                               return true
+                       }
+               }
+               return false
+       default:
+               // Func, Map, Slice, Invalid
+               panic("needKeyUpdate called on non-key type " + t.String())
+       }
+}
+
 // Make sure these routines stay in sync with ../../runtime/hashmap.go!
 // These types exist only for GC, so we only fill out GC relevant info.
 // Currently, that's just size and the GC program.  We also fill in string
index 8374370cfa66db4e9bc6afb23db21b9d6a7268c0..0f0eb846fc2c5cab0e9deeb29dc1e48ed4641f06 100644 (file)
@@ -143,7 +143,7 @@ func unpackEface(i interface{}) Value {
        if ifaceIndir(t) {
                f |= flagIndir
        }
-       return Value{t, unsafe.Pointer(e.word), f}
+       return Value{t, e.word, f}
 }
 
 // A ValueError occurs when a Value method is invoked on
@@ -507,7 +507,7 @@ func storeRcvr(v Value, p unsafe.Pointer) {
        if t.Kind() == Interface {
                // the interface data word becomes the receiver word
                iface := (*nonEmptyInterface)(v.ptr)
-               *(*unsafe.Pointer)(p) = unsafe.Pointer(iface.word)
+               *(*unsafe.Pointer)(p) = iface.word
        } else if v.flag&flagIndir != 0 && !ifaceIndir(t) {
                *(*unsafe.Pointer)(p) = *(*unsafe.Pointer)(v.ptr)
        } else {
@@ -1958,11 +1958,10 @@ func ValueOf(i interface{}) Value {
                return Value{}
        }
 
-       // TODO(rsc): Eliminate this terrible hack.
-       // In the call to unpackEface, i.typ doesn't escape,
-       // and i.word is an integer.  So it looks like
-       // i doesn't escape.  But really it does,
-       // because i.word is actually a pointer.
+       // TODO: Maybe allow contents of a Value to live on the stack.
+       // For now we make the contents always escape to the heap.  It
+       // makes life easier in a few places (see chanrecv/mapassign
+       // comment below).
        escapes(i)
 
        return unpackEface(i)
@@ -2318,6 +2317,14 @@ func chancap(ch unsafe.Pointer) int
 func chanclose(ch unsafe.Pointer)
 func chanlen(ch unsafe.Pointer) int
 
+// Note: some of the noescape annotations below are technically a lie,
+// but safe in the context of this package.  Functions like chansend
+// and mapassign don't escape the referent, but may escape anything
+// the referent points to (they do shallow copies of the referent).
+// It is safe in this package because the referent may only point
+// to something a Value may point to, and that is always in the heap
+// (due to the escapes() call in ValueOf).
+
 //go:noescape
 func chanrecv(t *rtype, ch unsafe.Pointer, nb bool, val unsafe.Pointer) (selected, received bool)
 
@@ -2330,6 +2337,7 @@ func makemap(t *rtype) (m unsafe.Pointer)
 //go:noescape
 func mapaccess(t *rtype, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer)
 
+//go:noescape
 func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer)
 
 //go:noescape
index d78ae6a4cdedc85dc9a46b10d89cc9dfaa066e2f..88391ff47decd531c4266dc756689f8265246de9 100644 (file)
@@ -113,6 +113,25 @@ func TestMatchFunction(t *testing.T) {
        }
 }
 
+func copyMatchTest(t *testing.T, test *FindTest) {
+       re := compileTest(t, test.pat, "")
+       if re == nil {
+               return
+       }
+       m1 := re.MatchString(test.text)
+       m2 := re.Copy().MatchString(test.text)
+       if m1 != m2 {
+               t.Errorf("Copied Regexp match failure on %s: original gave %t; copy gave %t; should be %t",
+                       test, m1, m2, len(test.matches) > 0)
+       }
+}
+
+func TestCopyMatch(t *testing.T) {
+       for _, test := range findTests {
+               copyMatchTest(t, &test)
+       }
+}
+
 type ReplaceTest struct {
        pattern, replacement, input, output string
 }
@@ -201,6 +220,12 @@ var replaceTests = []ReplaceTest{
        // Substitution when subexpression isn't found
        {"(x)?", "$1", "123", "123"},
        {"abc", "$1", "123", "123"},
+
+       // Substitutions involving a (x){0}
+       {"(a)(b){0}(c)", ".$1|$3.", "xacxacx", "x.a|c.x.a|c.x"},
+       {"(a)(((b))){0}c", ".$1.", "xacxacx", "x.a.x.a.x"},
+       {"((a(b){0}){3}){5}(h)", "y caramb$2", "say aaaaaaaaaaaaaaaah", "say ay caramba"},
+       {"((a(b){0}){3}){5}h", "y caramb$2", "say aaaaaaaaaaaaaaaah", "say ay caramba"},
 }
 
 var replaceLiteralTests = []ReplaceTest{
@@ -334,6 +359,19 @@ var metaTests = []MetaTest{
        {`!@#$%^&*()_+-=[{]}\|,<.>/?~`, `!@#\$%\^&\*\(\)_\+-=\[\{\]\}\\\|,<\.>/\?~`, `!@#`, false},
 }
 
+var literalPrefixTests = []MetaTest{
+       // See golang.org/issue/11175.
+       // output is unused.
+       {`^0^0$`, ``, `0`, false},
+       {`^0^`, ``, ``, false},
+       {`^0$`, ``, `0`, true},
+       {`$0^`, ``, ``, false},
+       {`$0$`, ``, ``, false},
+       {`^^0$$`, ``, ``, false},
+       {`^$^$`, ``, ``, false},
+       {`$$0^^`, ``, ``, false},
+}
+
 func TestQuoteMeta(t *testing.T) {
        for _, tc := range metaTests {
                // Verify that QuoteMeta returns the expected string.
@@ -365,7 +403,7 @@ func TestQuoteMeta(t *testing.T) {
 }
 
 func TestLiteralPrefix(t *testing.T) {
-       for _, tc := range metaTests {
+       for _, tc := range append(metaTests, literalPrefixTests...) {
                // Literal method needs to scan the pattern.
                re := MustCompile(tc.pattern)
                str, complete := re.LiteralPrefix()
@@ -665,3 +703,26 @@ func BenchmarkOnePassLongNotPrefix(b *testing.B) {
                re.Match(x)
        }
 }
+
+func BenchmarkMatchParallelShared(b *testing.B) {
+       x := []byte("this is a long line that contains foo bar baz")
+       re := MustCompile("foo (ba+r)? baz")
+       b.ResetTimer()
+       b.RunParallel(func(pb *testing.PB) {
+               for pb.Next() {
+                       re.Match(x)
+               }
+       })
+}
+
+func BenchmarkMatchParallelCopied(b *testing.B) {
+       x := []byte("this is a long line that contains foo bar baz")
+       re := MustCompile("foo (ba+r)? baz")
+       b.ResetTimer()
+       b.RunParallel(func(pb *testing.PB) {
+               re := re.Copy()
+               for pb.Next() {
+                       re.Match(x)
+               }
+       })
+}
index e6f42856387bc1ffc8efe9bd6ea714bc45dfa127..2ce3902388b292e411deb3b2e5b3cf19076cfb6c 100644 (file)
@@ -59,7 +59,12 @@ func onePassPrefix(p *syntax.Prog) (prefix string, complete bool, pc uint32) {
                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
+       if i.Op == syntax.InstEmptyWidth &&
+               syntax.EmptyOp(i.Arg)&syntax.EmptyEndText != 0 &&
+               p.Inst[i.Out].Op == syntax.InstMatch {
+               complete = true
+       }
+       return buf.String(), complete, pc
 }
 
 // OnePassNext selects the next actionable state of the prog, based on the input character.
@@ -108,10 +113,6 @@ func (q *queueOnePass) clear() {
        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
@@ -308,25 +309,9 @@ func makeOnePass(p *onePassProg) *onePassProg {
        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
@@ -385,11 +370,11 @@ func makeOnePass(p *onePassProg) *onePassProg {
                        m[pc] = inst.Op == syntax.InstMatch
                        break
                case syntax.InstRune:
-                       ok = check(inst.Out, m)
                        m[pc] = false
                        if len(inst.Next) > 0 {
                                break
                        }
+                       instQueue.insert(inst.Out)
                        if len(inst.Rune) == 0 {
                                onePassRunes[pc] = []rune{}
                                inst.Next = []uint32{inst.Out}
@@ -413,11 +398,11 @@ func makeOnePass(p *onePassProg) *onePassProg {
                        }
                        inst.Op = syntax.InstRune
                case syntax.InstRune1:
-                       ok = check(inst.Out, m)
                        m[pc] = false
                        if len(inst.Next) > 0 {
                                break
                        }
+                       instQueue.insert(inst.Out)
                        runes := []rune{}
                        // expand case-folded runes
                        if syntax.Flags(inst.Arg)&syntax.FoldCase != 0 {
@@ -437,19 +422,19 @@ func makeOnePass(p *onePassProg) *onePassProg {
                        }
                        inst.Op = syntax.InstRune
                case syntax.InstRuneAny:
-                       ok = check(inst.Out, m)
                        m[pc] = false
                        if len(inst.Next) > 0 {
                                break
                        }
+                       instQueue.insert(inst.Out)
                        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
                        }
+                       instQueue.insert(inst.Out)
                        onePassRunes[pc] = append([]rune{}, anyRuneNotNL...)
                        inst.Next = []uint32{}
                        for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
@@ -463,24 +448,12 @@ func makeOnePass(p *onePassProg) *onePassProg {
        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()
+               pc := instQueue.next()
                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 {
@@ -490,47 +463,6 @@ func makeOnePass(p *onePassProg) *onePassProg {
        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
index 7b2beea67ffb2a60f8c8e7debc358a3dea4ca500..8202ebefa59348dd5fb31e1732543e952468b8bd 100644 (file)
@@ -140,47 +140,41 @@ 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`},
+       {`^(?:a|(?:a*))$`, notOnePass},
+       {`^(?:(a)|(?:a*))$`, notOnePass},
+       {`^(?:(?:(?:.(?:$))?))$`, onePass},
+       {`^abcd$`, onePass},
+       {`^(?:(?:a{0,})*?)$`, onePass},
+       {`^(?:(?:a+)*)$`, onePass},
+       {`^(?:(?:a|(?:aa)))$`, onePass},
+       {`^(?:[^\s\S])$`, onePass},
+       {`^(?:(?:a{3,4}){0,})$`, notOnePass},
+       {`^(?:(?:(?:a*)+))$`, onePass},
+       {`^[a-c]+$`, onePass},
+       {`^[a-c]*$`, onePass},
+       {`^(?:a*)$`, onePass},
+       {`^(?:(?:aa)|a)$`, onePass},
+       {`^[a-c]*`, notOnePass},
+       {`^...$`, onePass},
+       {`^(?:a|(?:aa))$`, onePass},
+       {`^a((b))c$`, onePass},
+       {`^a.[l-nA-Cg-j]?e$`, onePass},
+       {`^a((b))$`, onePass},
+       {`^a(?:(b)|(c))c$`, onePass},
+       {`^a(?:(b*)|(c))c$`, notOnePass},
+       {`^a(?:b|c)$`, onePass},
+       {`^a(?:b?|c)$`, onePass},
+       {`^a(?:b?|c?)$`, notOnePass},
+       {`^a(?:b?|c+)$`, onePass},
+       {`^a(?:b+|(bc))d$`, notOnePass},
+       {`^a(?:bc)+$`, onePass},
+       {`^a(?:[bcd])+$`, onePass},
+       {`^a((?:[bcd])+)$`, onePass},
+       {`^a(:?b|c)*d$`, onePass},
+       {`^.bc(d|e)*$`, onePass},
+       {`^(?:(?:aa)|.)$`, notOnePass},
+       {`^(?:(?:a{1,2}){1,2})$`, notOnePass},
 }
 
 func TestCompileOnePass(t *testing.T) {
@@ -206,3 +200,28 @@ func TestCompileOnePass(t *testing.T) {
                }
        }
 }
+
+// TODO(cespare): Unify with onePassTests and rationalize one-pass test cases.
+var onePassTests1 = []struct {
+       re    string
+       match string
+}{
+       {`^a(/b+(#c+)*)*$`, "a/b#c"}, // golang.org/issue/11905
+}
+
+func TestRunOnePass(t *testing.T) {
+       for _, test := range onePassTests1 {
+               re, err := Compile(test.re)
+               if err != nil {
+                       t.Errorf("Compile(%q): got err: %s", test.re, err)
+                       continue
+               }
+               if re.onepass == notOnePass {
+                       t.Errorf("Compile(%q): got notOnePass, want one-pass", test.re)
+                       continue
+               }
+               if !re.MatchString(test.match) {
+                       t.Errorf("onepass %q did not match %q", test.re, test.match)
+               }
+       }
+}
index 4e4b41242a3749662835ef1874244d475d67b021..d7d0edb993f3a0b07fab8c163fbd72fc181ae9df 100644 (file)
@@ -104,6 +104,17 @@ func (re *Regexp) String() string {
        return re.expr
 }
 
+// Copy returns a new Regexp object copied from re.
+//
+// When using a Regexp in multiple goroutines, giving each goroutine
+// its own copy helps to avoid lock contention.
+func (re *Regexp) Copy() *Regexp {
+       r := *re
+       r.mu = sync.Mutex{}
+       r.machine = nil
+       return &r
+}
+
 // Compile parses a regular expression and returns, if successful,
 // a Regexp object that can be used to match against text.
 //
@@ -482,6 +493,10 @@ func (re *Regexp) replaceAll(bsrc []byte, src string, nmatch int, repl func(dst
        } else {
                endPos = len(src)
        }
+       if nmatch > re.prog.NumCap {
+               nmatch = re.prog.NumCap
+       }
+
        for searchPos <= endPos {
                a := re.doExecute(nil, bsrc, src, searchPos, nmatch)
                if len(a) == 0 {
index d579a4069b16021b11438e9d04543c2d6c68d028..f38bbf66e3cf47c8420151413f00b31c720a1b15 100644 (file)
@@ -470,9 +470,14 @@ func (p *parser) factor(sub []*Regexp, flags Flags) []*Regexp {
        }
        sub = out
 
-       // Round 2: Factor out common complex prefixes,
-       // just the first piece of each concatenation,
-       // whatever it is.  This is good enough a lot of the time.
+       // Round 2: Factor out common simple prefixes,
+       // just the first piece of each concatenation.
+       // This will be good enough a lot of the time.
+       //
+       // Complex subexpressions (e.g. involving quantifiers)
+       // are not safe to factor because that collapses their
+       // distinct paths through the automaton, which affects
+       // correctness in some cases.
        start = 0
        out = sub[:0]
        var first *Regexp
@@ -485,7 +490,9 @@ func (p *parser) factor(sub []*Regexp, flags Flags) []*Regexp {
                var ifirst *Regexp
                if i < len(sub) {
                        ifirst = p.leadingRegexp(sub[i])
-                       if first != nil && first.Equal(ifirst) {
+                       if first != nil && first.Equal(ifirst) &&
+                               // first must be a character class OR a fixed repeat of a character class.
+                               (isCharClass(first) || (first.Op == OpRepeat && first.Min == first.Max && isCharClass(first.Sub[0]))) {
                                continue
                        }
                }
@@ -830,7 +837,14 @@ func Parse(s string, flags Flags) (*Regexp, error) {
                                                lit = t[2:i]
                                                t = t[i+2:]
                                        }
-                                       p.push(literalRegexp(lit, p.flags))
+                                       for lit != "" {
+                                               c, rest, err := nextRune(lit)
+                                               if err != nil {
+                                                       return nil, err
+                                               }
+                                               p.literal(c)
+                                               lit = rest
+                                       }
                                        break BigSwitch
                                case 'z':
                                        p.op(OpEndText)
index c4a1117ff86ced2e46b04c9f68e593eed383d7ff..5ca54bbe1ebdf5467909fea225d4878d819a8090 100644 (file)
@@ -144,6 +144,7 @@ var parseTests = []parseTest{
        // Test Perl quoted literals
        {`\Q+|*?{[\E`, `str{+|*?{[}`},
        {`\Q+\E+`, `plus{lit{+}}`},
+       {`\Qab\E+`, `cat{lit{a}plus{lit{b}}}`},
        {`\Q\\E`, `lit{\}`},
        {`\Q\\\E`, `str{\\}`},
 
@@ -171,7 +172,7 @@ var parseTests = []parseTest{
 
        // Factoring.
        {`abc|abd|aef|bcx|bcy`, `alt{cat{lit{a}alt{cat{lit{b}cc{0x63-0x64}}str{ef}}}cat{str{bc}cc{0x78-0x79}}}`},
-       {`ax+y|ax+z|ay+w`, `cat{lit{a}alt{cat{plus{lit{x}}cc{0x79-0x7a}}cat{plus{lit{y}}lit{w}}}}`},
+       {`ax+y|ax+z|ay+w`, `cat{lit{a}alt{cat{plus{lit{x}}lit{y}}cat{plus{lit{x}}lit{z}}cat{plus{lit{y}}lit{w}}}}`},
 
        // Bug fixes.
        {`(?:.)`, `dot{}`},
@@ -194,12 +195,13 @@ var parseTests = []parseTest{
        {`abc|x|abd`, `alt{str{abc}lit{x}str{abd}}`},
        {`(?i)abc|ABD`, `cat{strfold{AB}cc{0x43-0x44 0x63-0x64}}`},
        {`[ab]c|[ab]d`, `cat{cc{0x61-0x62}cc{0x63-0x64}}`},
-       {`(?:xx|yy)c|(?:xx|yy)d`,
-               `cat{alt{str{xx}str{yy}}cc{0x63-0x64}}`},
+       {`.c|.d`, `cat{dot{}cc{0x63-0x64}}`},
        {`x{2}|x{2}[0-9]`,
                `cat{rep{2,2 lit{x}}alt{emp{}cc{0x30-0x39}}}`},
        {`x{2}y|x{2}[0-9]y`,
                `cat{rep{2,2 lit{x}}alt{lit{y}cat{cc{0x30-0x39}lit{y}}}}`},
+       {`a.*?c|a.*?b`,
+               `cat{lit{a}alt{cat{nstar{dot{}}lit{c}}cat{nstar{dot{}}lit{b}}}}`},
 
        // Valid repetitions.
        {`((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}))`, ``},
@@ -479,6 +481,7 @@ var invalidRegexps = []string{
        `a{100000}`,
        `a{100000,}`,
        "((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}){2})",
+       `\Q\E*`,
 }
 
 var onlyPerl = []string{
index cea7d9e04fec70ac66435c0aae94398b07a57ba2..75822cf981e3442868cc1b20e8287b19ea394abd 100644 (file)
@@ -166,9 +166,9 @@ func writeRegexp(b *bytes.Buffer, re *Regexp) {
        case OpAnyChar:
                b.WriteString(`(?s:.)`)
        case OpBeginLine:
-               b.WriteRune('^')
+               b.WriteString(`(?m:^)`)
        case OpEndLine:
-               b.WriteRune('$')
+               b.WriteString(`(?m:$)`)
        case OpBeginText:
                b.WriteString(`\A`)
        case OpEndText:
index 879eff5be7ee3d9aa25489fb10180a708b633125..5d0f1dea5e738b5d3525c9b3e3c2064c6ebccd39 100644 (file)
@@ -19,8 +19,8 @@ var simplifyTests = []struct {
        {`(ab)+`, `(ab)+`},
        {`(ab)?`, `(ab)?`},
        {`.`, `(?s:.)`},
-       {`^`, `^`},
-       {`$`, `$`},
+       {`^`, `(?m:^)`},
+       {`$`, `(?m:$)`},
        {`[ac]`, `[ac]`},
        {`[^ac]`, `[^ac]`},
 
index f648e5527f7633d0074159aa1866899ead11bacb..4d02e9cebd687a01767295533905bd5c8ae56b8f 100644 (file)
@@ -3665,3 +3665,8 @@ regexps
 "(?:a\\C*|ba\\C)$"
 -;-;-;-
 -;1-4;-;1-4
+strings
+"abc"
+regexps
+"a.*?c|a.*?b"
+0-3;0-3;0-3;0-3
diff --git a/libgo/go/runtime/cgo_mmap.go b/libgo/go/runtime/cgo_mmap.go
new file mode 100644 (file)
index 0000000..ef5501c
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2015 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.
+
+// Support for memory sanitizer.  See runtime/cgo/mmap.go.
+
+// +build linux,amd64
+
+package runtime
+
+import "unsafe"
+
+// _cgo_mmap is filled in by runtime/cgo when it is linked into the
+// program, so it is only non-nil when using cgo.
+//go:linkname _cgo_mmap _cgo_mmap
+var _cgo_mmap unsafe.Pointer
+
+func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) (ret unsafe.Pointer) {
+       if _cgo_mmap != nil {
+               systemstack(func() {
+                       ret = callCgoMmap(addr, n, prot, flags, fd, off)
+               })
+               return
+       }
+       return sysMmap(addr, n, prot, flags, fd, off)
+}
+
+// sysMmap calls the mmap system call.  It is implemented in assembly.
+func sysMmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
+
+// cgoMmap calls the mmap function in the runtime/cgo package on the
+// callCgoMmap calls the mmap function in the runtime/cgo package
+// using the GCC calling convention.  It is implemented in assembly.
+func callCgoMmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
diff --git a/libgo/go/runtime/cgo_ppc64x.go b/libgo/go/runtime/cgo_ppc64x.go
new file mode 100644 (file)
index 0000000..6a1b3bb
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2015 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 ppc64 ppc64le
+
+package runtime
+
+// crosscall_ppc64 calls into the runtime to set up the registers the
+// Go runtime expects and so the symbol it calls needs to be exported
+// for external linking to work.
+//go:cgo_export_static _cgo_reginit
diff --git a/libgo/go/runtime/cgocheck.go b/libgo/go/runtime/cgocheck.go
new file mode 100644 (file)
index 0000000..0077e22
--- /dev/null
@@ -0,0 +1,243 @@
+// Copyright 2015 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.
+
+// Code to check that pointer writes follow the cgo rules.
+// These functions are invoked via the write barrier when debug.cgocheck > 1.
+
+package runtime
+
+import (
+       "runtime/internal/sys"
+       "unsafe"
+)
+
+const cgoWriteBarrierFail = "Go pointer stored into non-Go memory"
+
+// cgoCheckWriteBarrier is called whenever a pointer is stored into memory.
+// It throws if the program is storing a Go pointer into non-Go memory.
+//go:nosplit
+//go:nowritebarrier
+func cgoCheckWriteBarrier(dst *uintptr, src uintptr) {
+       if !cgoIsGoPointer(unsafe.Pointer(src)) {
+               return
+       }
+       if cgoIsGoPointer(unsafe.Pointer(dst)) {
+               return
+       }
+
+       // If we are running on the system stack then dst might be an
+       // address on the stack, which is OK.
+       g := getg()
+       if g == g.m.g0 || g == g.m.gsignal {
+               return
+       }
+
+       // Allocating memory can write to various mfixalloc structs
+       // that look like they are non-Go memory.
+       if g.m.mallocing != 0 {
+               return
+       }
+
+       systemstack(func() {
+               println("write of Go pointer", hex(src), "to non-Go memory", hex(uintptr(unsafe.Pointer(dst))))
+               throw(cgoWriteBarrierFail)
+       })
+}
+
+// cgoCheckMemmove is called when moving a block of memory.
+// dst and src point off bytes into the value to copy.
+// size is the number of bytes to copy.
+// It throws if the program is copying a block that contains a Go pointer
+// into non-Go memory.
+//go:nosplit
+//go:nowritebarrier
+func cgoCheckMemmove(typ *_type, dst, src unsafe.Pointer, off, size uintptr) {
+       if typ.kind&kindNoPointers != 0 {
+               return
+       }
+       if !cgoIsGoPointer(src) {
+               return
+       }
+       if cgoIsGoPointer(dst) {
+               return
+       }
+       cgoCheckTypedBlock(typ, src, off, size)
+}
+
+// cgoCheckSliceCopy is called when copying n elements of a slice from
+// src to dst.  typ is the element type of the slice.
+// It throws if the program is copying slice elements that contain Go pointers
+// into non-Go memory.
+//go:nosplit
+//go:nowritebarrier
+func cgoCheckSliceCopy(typ *_type, dst, src slice, n int) {
+       if typ.kind&kindNoPointers != 0 {
+               return
+       }
+       if !cgoIsGoPointer(src.array) {
+               return
+       }
+       if cgoIsGoPointer(dst.array) {
+               return
+       }
+       p := src.array
+       for i := 0; i < n; i++ {
+               cgoCheckTypedBlock(typ, p, 0, typ.size)
+               p = add(p, typ.size)
+       }
+}
+
+// cgoCheckTypedBlock checks the block of memory at src, for up to size bytes,
+// and throws if it finds a Go pointer.  The type of the memory is typ,
+// and src is off bytes into that type.
+//go:nosplit
+//go:nowritebarrier
+func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) {
+       if typ.kind&kindGCProg == 0 {
+               cgoCheckBits(src, typ.gcdata, off, size)
+               return
+       }
+
+       // The type has a GC program.  Try to find GC bits somewhere else.
+       for datap := &firstmoduledata; datap != nil; datap = datap.next {
+               if cgoInRange(src, datap.data, datap.edata) {
+                       doff := uintptr(src) - datap.data
+                       cgoCheckBits(add(src, -doff), datap.gcdatamask.bytedata, off+doff, size)
+                       return
+               }
+               if cgoInRange(src, datap.bss, datap.ebss) {
+                       boff := uintptr(src) - datap.bss
+                       cgoCheckBits(add(src, -boff), datap.gcbssmask.bytedata, off+boff, size)
+                       return
+               }
+       }
+
+       aoff := uintptr(src) - mheap_.arena_start
+       idx := aoff >> _PageShift
+       s := h_spans[idx]
+       if s.state == _MSpanStack {
+               // There are no heap bits for value stored on the stack.
+               // For a channel receive src might be on the stack of some
+               // other goroutine, so we can't unwind the stack even if
+               // we wanted to.
+               // We can't expand the GC program without extra storage
+               // space we can't easily get.
+               // Fortunately we have the type information.
+               systemstack(func() {
+                       cgoCheckUsingType(typ, src, off, size)
+               })
+               return
+       }
+
+       // src must be in the regular heap.
+
+       hbits := heapBitsForAddr(uintptr(src))
+       for i := uintptr(0); i < off+size; i += sys.PtrSize {
+               bits := hbits.bits()
+               if bits != 0 {
+                       println(i, bits)
+               }
+               if i >= off && bits&bitPointer != 0 {
+                       v := *(*unsafe.Pointer)(add(src, i))
+                       if cgoIsGoPointer(v) {
+                               systemstack(func() {
+                                       throw(cgoWriteBarrierFail)
+                               })
+                       }
+               }
+               hbits = hbits.next()
+       }
+}
+
+// cgoCheckBits checks the block of memory at src, for up to size
+// bytes, and throws if it finds a Go pointer.  The gcbits mark each
+// pointer value.  The src pointer is off bytes into the gcbits.
+//go:nosplit
+//go:nowritebarrier
+func cgoCheckBits(src unsafe.Pointer, gcbits *byte, off, size uintptr) {
+       skipMask := off / sys.PtrSize / 8
+       skipBytes := skipMask * sys.PtrSize * 8
+       ptrmask := addb(gcbits, skipMask)
+       src = add(src, skipBytes)
+       off -= skipBytes
+       size += off
+       var bits uint32
+       for i := uintptr(0); i < size; i += sys.PtrSize {
+               if i&(sys.PtrSize*8-1) == 0 {
+                       bits = uint32(*ptrmask)
+                       ptrmask = addb(ptrmask, 1)
+               } else {
+                       bits >>= 1
+               }
+               if off > 0 {
+                       off -= sys.PtrSize
+               } else {
+                       if bits&1 != 0 {
+                               v := *(*unsafe.Pointer)(add(src, i))
+                               if cgoIsGoPointer(v) {
+                                       systemstack(func() {
+                                               throw(cgoWriteBarrierFail)
+                                       })
+                               }
+                       }
+               }
+       }
+}
+
+// cgoCheckUsingType is like cgoCheckTypedBlock, but is a last ditch
+// fall back to look for pointers in src using the type information.
+// We only this when looking at a value on the stack when the type
+// uses a GC program, because otherwise it's more efficient to use the
+// GC bits.  This is called on the system stack.
+//go:nowritebarrier
+//go:systemstack
+func cgoCheckUsingType(typ *_type, src unsafe.Pointer, off, size uintptr) {
+       if typ.kind&kindNoPointers != 0 {
+               return
+       }
+       if typ.kind&kindGCProg == 0 {
+               cgoCheckBits(src, typ.gcdata, off, size)
+               return
+       }
+       switch typ.kind & kindMask {
+       default:
+               throw("can't happen")
+       case kindArray:
+               at := (*arraytype)(unsafe.Pointer(typ))
+               for i := uintptr(0); i < at.len; i++ {
+                       if off < at.elem.size {
+                               cgoCheckUsingType(at.elem, src, off, size)
+                       }
+                       src = add(src, at.elem.size)
+                       skipped := off
+                       if skipped > at.elem.size {
+                               skipped = at.elem.size
+                       }
+                       checked := at.elem.size - skipped
+                       off -= skipped
+                       if size <= checked {
+                               return
+                       }
+                       size -= checked
+               }
+       case kindStruct:
+               st := (*structtype)(unsafe.Pointer(typ))
+               for _, f := range st.fields {
+                       if off < f.typ.size {
+                               cgoCheckUsingType(f.typ, src, off, size)
+                       }
+                       src = add(src, f.typ.size)
+                       skipped := off
+                       if skipped > f.typ.size {
+                               skipped = f.typ.size
+                       }
+                       checked := f.typ.size - skipped
+                       off -= skipped
+                       if size <= checked {
+                               return
+                       }
+                       size -= checked
+               }
+       }
+}
index 2e65e4c7543378549bc6316bd206fc0525cb8f28..d7b367f941f4a35e89a8d77828e105e2757dd97a 100644 (file)
@@ -21,18 +21,18 @@ func TestCgoSignalDeadlock(t *testing.T) {
        if testing.Short() && runtime.GOOS == "windows" {
                t.Skip("Skipping in short mode") // takes up to 64 seconds
        }
-       got := executeTest(t, cgoSignalDeadlockSource, nil)
+       got := runTestProg(t, "testprogcgo", "CgoSignalDeadlock")
        want := "OK\n"
        if got != want {
-               t.Fatalf("expected %q, but got %q", want, got)
+               t.Fatalf("expected %q, but got:\n%s", want, got)
        }
 }
 
 func TestCgoTraceback(t *testing.T) {
-       got := executeTest(t, cgoTracebackSource, nil)
+       got := runTestProg(t, "testprogcgo", "CgoTraceback")
        want := "OK\n"
        if got != want {
-               t.Fatalf("expected %q, but got %q", want, got)
+               t.Fatalf("expected %q, but got:\n%s", want, got)
        }
 }
 
@@ -40,13 +40,18 @@ func TestCgoCallbackGC(t *testing.T) {
        if runtime.GOOS == "plan9" || runtime.GOOS == "windows" {
                t.Skipf("no pthreads on %s", runtime.GOOS)
        }
-       if testing.Short() && runtime.GOOS == "dragonfly" {
-               t.Skip("see golang.org/issue/11990")
+       if testing.Short() {
+               switch {
+               case runtime.GOOS == "dragonfly":
+                       t.Skip("see golang.org/issue/11990")
+               case runtime.GOOS == "linux" && runtime.GOARCH == "arm":
+                       t.Skip("too slow for arm builders")
+               }
        }
-       got := executeTest(t, cgoCallbackGCSource, nil)
+       got := runTestProg(t, "testprogcgo", "CgoCallbackGC")
        want := "OK\n"
        if got != want {
-               t.Fatalf("expected %q, but got %q", want, got)
+               t.Fatalf("expected %q, but got:\n%s", want, got)
        }
 }
 
@@ -54,11 +59,7 @@ func TestCgoExternalThreadPanic(t *testing.T) {
        if runtime.GOOS == "plan9" {
                t.Skipf("no pthreads on %s", runtime.GOOS)
        }
-       csrc := cgoExternalThreadPanicC
-       if runtime.GOOS == "windows" {
-               csrc = cgoExternalThreadPanicC_windows
-       }
-       got := executeTest(t, cgoExternalThreadPanicSource, nil, "main.c", csrc)
+       got := runTestProg(t, "testprogcgo", "CgoExternalThreadPanic")
        want := "panic: BOOM"
        if !strings.Contains(got, want) {
                t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
@@ -84,15 +85,15 @@ func TestCgoExternalThreadSIGPROF(t *testing.T) {
                        }
                }
        }
-       if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" {
+       if runtime.GOARCH == "ppc64" {
                // TODO(austin) External linking not implemented on
                // ppc64 (issue #8912)
                t.Skipf("no external linking on ppc64")
        }
-       got := executeTest(t, cgoExternalThreadSIGPROFSource, nil)
+       got := runTestProg(t, "testprogcgo", "CgoExternalThreadSIGPROF")
        want := "OK\n"
        if got != want {
-               t.Fatalf("expected %q, but got %q", want, got)
+               t.Fatalf("expected %q, but got:\n%s", want, got)
        }
 }
 
@@ -102,10 +103,10 @@ func TestCgoExternalThreadSignal(t *testing.T) {
        case "plan9", "windows":
                t.Skipf("no pthreads on %s", runtime.GOOS)
        }
-       got := executeTest(t, cgoExternalThreadSignalSource, nil)
+       got := runTestProg(t, "testprogcgo", "CgoExternalThreadSignal")
        want := "OK\n"
        if got != want {
-               t.Fatalf("expected %q, but got %q", want, got)
+               t.Fatalf("expected %q, but got:\n%s", want, got)
        }
 }
 
@@ -114,368 +115,35 @@ func TestCgoDLLImports(t *testing.T) {
        if runtime.GOOS != "windows" {
                t.Skip("skipping windows specific test")
        }
-       got := executeTest(t, cgoDLLImportsMainSource, nil, "a/a.go", cgoDLLImportsPkgSource)
+       got := runTestProg(t, "testprogcgo", "CgoDLLImportsMain")
        want := "OK\n"
        if got != want {
                t.Fatalf("expected %q, but got %v", want, got)
        }
 }
 
-const cgoSignalDeadlockSource = `
-package main
-
-import "C"
-
-import (
-       "fmt"
-       "runtime"
-       "time"
-)
-
-func main() {
-       runtime.GOMAXPROCS(100)
-       ping := make(chan bool)
-       go func() {
-               for i := 0; ; i++ {
-                       runtime.Gosched()
-                       select {
-                       case done := <-ping:
-                               if done {
-                                       ping <- true
-                                       return
-                               }
-                               ping <- true
-                       default:
-                       }
-                       func() {
-                               defer func() {
-                                       recover()
-                               }()
-                               var s *string
-                               *s = ""
-                       }()
-               }
-       }()
-       time.Sleep(time.Millisecond)
-       for i := 0; i < 64; i++ {
-               go func() {
-                       runtime.LockOSThread()
-                       select {}
-               }()
-               go func() {
-                       runtime.LockOSThread()
-                       select {}
-               }()
-               time.Sleep(time.Millisecond)
-               ping <- false
-               select {
-               case <-ping:
-               case <-time.After(time.Second):
-                       fmt.Printf("HANG\n")
-                       return
-               }
-       }
-       ping <- true
-       select {
-       case <-ping:
-       case <-time.After(time.Second):
-               fmt.Printf("HANG\n")
-               return
-       }
-       fmt.Printf("OK\n")
-}
-`
-
-const cgoTracebackSource = `
-package main
-
-/* void foo(void) {} */
-import "C"
-
-import (
-       "fmt"
-       "runtime"
-)
-
-func main() {
-       C.foo()
-       buf := make([]byte, 1)
-       runtime.Stack(buf, true)
-       fmt.Printf("OK\n")
-}
-`
-
-const cgoCallbackGCSource = `
-package main
-
-import "runtime"
-
-/*
-#include <pthread.h>
-
-void go_callback();
-
-static void *thr(void *arg) {
-    go_callback();
-    return 0;
-}
-
-static void foo() {
-    pthread_t th;
-    pthread_create(&th, 0, thr, 0);
-    pthread_join(th, 0);
-}
-*/
-import "C"
-import "fmt"
-
-//export go_callback
-func go_callback() {
-       runtime.GC()
-       grow()
-       runtime.GC()
-}
-
-var cnt int
-
-func grow() {
-       x := 10000
-       sum := 0
-       if grow1(&x, &sum) == 0 {
-               panic("bad")
-       }
-}
-
-func grow1(x, sum *int) int {
-       if *x == 0 {
-               return *sum + 1
-       }
-       *x--
-       sum1 := *sum + *x
-       return grow1(x, &sum1)
-}
-
-func main() {
-       const P = 100
-       done := make(chan bool)
-       // allocate a bunch of stack frames and spray them with pointers
-       for i := 0; i < P; i++ {
-               go func() {
-                       grow()
-                       done <- true
-               }()
-       }
-       for i := 0; i < P; i++ {
-               <-done
-       }
-       // now give these stack frames to cgo callbacks
-       for i := 0; i < P; i++ {
-               go func() {
-                       C.foo()
-                       done <- true
-               }()
-       }
-       for i := 0; i < P; i++ {
-               <-done
+func TestCgoExecSignalMask(t *testing.T) {
+       // Test issue 13164.
+       switch runtime.GOOS {
+       case "windows", "plan9":
+               t.Skipf("skipping signal mask test on %s", runtime.GOOS)
        }
-       fmt.Printf("OK\n")
-}
-`
-
-const cgoExternalThreadPanicSource = `
-package main
-
-// void start(void);
-import "C"
-
-func main() {
-       C.start()
-       select {}
-}
-
-//export gopanic
-func gopanic() {
-       panic("BOOM")
-}
-`
-
-const cgoExternalThreadPanicC = `
-#include <stdlib.h>
-#include <stdio.h>
-#include <pthread.h>
-
-void gopanic(void);
-
-static void*
-die(void* x)
-{
-       gopanic();
-       return 0;
-}
-
-void
-start(void)
-{
-       pthread_t t;
-       if(pthread_create(&t, 0, die, 0) != 0)
-               printf("pthread_create failed\n");
-}
-`
-
-const cgoExternalThreadPanicC_windows = `
-#include <stdlib.h>
-#include <stdio.h>
-
-void gopanic(void);
-
-static void*
-die(void* x)
-{
-       gopanic();
-       return 0;
-}
-
-void
-start(void)
-{
-       if(_beginthreadex(0, 0, die, 0, 0, 0) != 0)
-               printf("_beginthreadex failed\n");
-}
-`
-
-const cgoExternalThreadSIGPROFSource = `
-package main
-
-/*
-#include <stdint.h>
-#include <signal.h>
-#include <pthread.h>
-
-volatile int32_t spinlock;
-
-static void *thread1(void *p) {
-       (void)p;
-       while (spinlock == 0)
-               ;
-       pthread_kill(pthread_self(), SIGPROF);
-       spinlock = 0;
-       return NULL;
-}
-__attribute__((constructor)) void issue9456() {
-       pthread_t tid;
-       pthread_create(&tid, 0, thread1, NULL);
-}
-*/
-import "C"
-
-import (
-       "runtime"
-       "sync/atomic"
-       "unsafe"
-)
-
-func main() {
-       // This test intends to test that sending SIGPROF to foreign threads
-       // before we make any cgo call will not abort the whole process, so
-       // we cannot make any cgo call here. See https://golang.org/issue/9456.
-       atomic.StoreInt32((*int32)(unsafe.Pointer(&C.spinlock)), 1)
-       for atomic.LoadInt32((*int32)(unsafe.Pointer(&C.spinlock))) == 1 {
-               runtime.Gosched()
+       got := runTestProg(t, "testprogcgo", "CgoExecSignalMask")
+       want := "OK\n"
+       if got != want {
+               t.Errorf("expected %q, got %v", want, got)
        }
-       println("OK")
-}
-`
-
-const cgoExternalThreadSignalSource = `
-package main
-
-/*
-#include <pthread.h>
-
-void **nullptr;
-
-void *crash(void *p) {
-       *nullptr = p;
-       return 0;
 }
 
-int start_crashing_thread(void) {
-       pthread_t tid;
-       return pthread_create(&tid, 0, crash, 0);
-}
-*/
-import "C"
-
-import (
-       "fmt"
-       "os"
-       "os/exec"
-       "time"
-)
-
-func main() {
-       if len(os.Args) > 1 && os.Args[1] == "crash" {
-               i := C.start_crashing_thread()
-               if i != 0 {
-                       fmt.Println("pthread_create failed:", i)
-                       // Exit with 0 because parent expects us to crash.
-                       return
-               }
-
-               // We should crash immediately, but give it plenty of
-               // time before failing (by exiting 0) in case we are
-               // running on a slow system.
-               time.Sleep(5 * time.Second)
-               return
+func TestEnsureDropM(t *testing.T) {
+       // Test for issue 13881.
+       switch runtime.GOOS {
+       case "windows", "plan9":
+               t.Skipf("skipping dropm test on %s", runtime.GOOS)
        }
-
-       out, err := exec.Command(os.Args[0], "crash").CombinedOutput()
-       if err == nil {
-               fmt.Println("C signal did not crash as expected\n")
-               fmt.Printf("%s\n", out)
-               os.Exit(1)
+       got := runTestProg(t, "testprogcgo", "EnsureDropM")
+       want := "OK\n"
+       if got != want {
+               t.Errorf("expected %q, got %v", want, got)
        }
-
-       fmt.Println("OK")
-}
-`
-
-const cgoDLLImportsMainSource = `
-package main
-
-/*
-#include <windows.h>
-
-DWORD getthread() {
-       return GetCurrentThreadId();
-}
-*/
-import "C"
-
-import "./a"
-
-func main() {
-       C.getthread()
-       a.GetThread()
-       println("OK")
-}
-`
-
-const cgoDLLImportsPkgSource = `
-package a
-
-/*
-#cgo CFLAGS: -mnop-fun-dllimport
-
-#include <windows.h>
-
-DWORD agetthread() {
-       return GetCurrentThreadId();
-}
-*/
-import "C"
-
-func GetThread() uint32 {
-       return uint32(C.agetthread())
 }
-`
index 8efce4da2d4d5b626e6163dafa205f5b6f1bec1e..b622eb4526a8d63bbb5d846d9f0451a713636c13 100644 (file)
@@ -16,9 +16,18 @@ import (
        "strings"
        "sync"
        "testing"
-       "text/template"
 )
 
+var toRemove []string
+
+func TestMain(m *testing.M) {
+       status := m.Run()
+       for _, file := range toRemove {
+               os.RemoveAll(file)
+       }
+       os.Exit(status)
+}
+
 func testEnv(cmd *exec.Cmd) *exec.Cmd {
        if cmd.Env != nil {
                panic("environment already set")
@@ -38,55 +47,63 @@ func testEnv(cmd *exec.Cmd) *exec.Cmd {
        return cmd
 }
 
-func executeTest(t *testing.T, templ string, data interface{}, extra ...string) string {
-       testenv.MustHaveGoBuild(t)
+var testprog struct {
+       sync.Mutex
+       dir    string
+       target map[string]buildexe
+}
 
-       checkStaleRuntime(t)
+type buildexe struct {
+       exe string
+       err error
+}
 
-       st := template.Must(template.New("crashSource").Parse(templ))
+func runTestProg(t *testing.T, binary, name string) string {
+       testenv.MustHaveGoBuild(t)
 
-       dir, err := ioutil.TempDir("", "go-build")
+       exe, err := buildTestProg(t, binary)
        if err != nil {
-               t.Fatalf("failed to create temp directory: %v", err)
+               t.Fatal(err)
        }
-       defer os.RemoveAll(dir)
+       got, _ := testEnv(exec.Command(exe, name)).CombinedOutput()
+       return string(got)
+}
 
-       src := filepath.Join(dir, "main.go")
-       f, err := os.Create(src)
-       if err != nil {
-               t.Fatalf("failed to create file: %v", err)
-       }
-       err = st.Execute(f, data)
-       if err != nil {
-               f.Close()
-               t.Fatalf("failed to execute template: %v", err)
-       }
-       if err := f.Close(); err != nil {
-               t.Fatalf("failed to close file: %v", err)
-       }
+func buildTestProg(t *testing.T, binary string) (string, error) {
+       checkStaleRuntime(t)
 
-       for i := 0; i < len(extra); i += 2 {
-               fname := extra[i]
-               contents := extra[i+1]
-               if d, _ := filepath.Split(fname); d != "" {
-                       if err := os.Mkdir(filepath.Join(dir, d), 0755); err != nil {
-                               t.Fatal(err)
-                       }
-               }
-               if err := ioutil.WriteFile(filepath.Join(dir, fname), []byte(contents), 0666); err != nil {
-                       t.Fatal(err)
+       testprog.Lock()
+       defer testprog.Unlock()
+       if testprog.dir == "" {
+               dir, err := ioutil.TempDir("", "go-build")
+               if err != nil {
+                       t.Fatalf("failed to create temp directory: %v", err)
                }
+               testprog.dir = dir
+               toRemove = append(toRemove, dir)
+       }
+
+       if testprog.target == nil {
+               testprog.target = make(map[string]buildexe)
+       }
+       target, ok := testprog.target[binary]
+       if ok {
+               return target.exe, target.err
        }
 
-       cmd := exec.Command("go", "build", "-o", "a.exe")
-       cmd.Dir = dir
+       exe := filepath.Join(testprog.dir, binary+".exe")
+       cmd := exec.Command("go", "build", "-o", exe)
+       cmd.Dir = "testdata/" + binary
        out, err := testEnv(cmd).CombinedOutput()
        if err != nil {
-               t.Fatalf("building source: %v\n%s", err, out)
+               exe = ""
+               target.err = fmt.Errorf("building %s: %v\n%s", binary, err, out)
+               testprog.target[binary] = target
+               return "", target.err
        }
-
-       got, _ := testEnv(exec.Command(filepath.Join(dir, "a.exe"))).CombinedOutput()
-       return string(got)
+       target.exe = exe
+       testprog.target[binary] = target
+       return exe, nil
 }
 
 var (
@@ -115,7 +132,12 @@ func testCrashHandler(t *testing.T, cgo bool) {
        type crashTest struct {
                Cgo bool
        }
-       output := executeTest(t, crashSource, &crashTest{Cgo: cgo})
+       var output string
+       if cgo {
+               output = runTestProg(t, "testprogcgo", "Crash")
+       } else {
+               output = runTestProg(t, "testprog", "Crash")
+       }
        want := "main: recovered done\nnew-thread: recovered done\nsecond-new-thread: recovered done\nmain-again: recovered done\n"
        if output != want {
                t.Fatalf("output:\n%s\n\nwanted:\n%s", output, want)
@@ -126,8 +148,8 @@ func TestCrashHandler(t *testing.T) {
        testCrashHandler(t, false)
 }
 
-func testDeadlock(t *testing.T, source string) {
-       output := executeTest(t, source, nil)
+func testDeadlock(t *testing.T, name string) {
+       output := runTestProg(t, "testprog", name)
        want := "fatal error: all goroutines are asleep - deadlock!\n"
        if !strings.HasPrefix(output, want) {
                t.Fatalf("output does not start with %q:\n%s", want, output)
@@ -135,23 +157,23 @@ func testDeadlock(t *testing.T, source string) {
 }
 
 func TestSimpleDeadlock(t *testing.T) {
-       testDeadlock(t, simpleDeadlockSource)
+       testDeadlock(t, "SimpleDeadlock")
 }
 
 func TestInitDeadlock(t *testing.T) {
-       testDeadlock(t, initDeadlockSource)
+       testDeadlock(t, "InitDeadlock")
 }
 
 func TestLockedDeadlock(t *testing.T) {
-       testDeadlock(t, lockedDeadlockSource)
+       testDeadlock(t, "LockedDeadlock")
 }
 
 func TestLockedDeadlock2(t *testing.T) {
-       testDeadlock(t, lockedDeadlockSource2)
+       testDeadlock(t, "LockedDeadlock2")
 }
 
 func TestGoexitDeadlock(t *testing.T) {
-       output := executeTest(t, goexitDeadlockSource, nil)
+       output := runTestProg(t, "testprog", "GoexitDeadlock")
        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)
@@ -159,15 +181,15 @@ func TestGoexitDeadlock(t *testing.T) {
 }
 
 func TestStackOverflow(t *testing.T) {
-       output := executeTest(t, stackOverflowSource, nil)
-       want := "runtime: goroutine stack exceeds 4194304-byte limit\nfatal error: stack overflow"
+       output := runTestProg(t, "testprog", "StackOverflow")
+       want := "runtime: goroutine stack exceeds 1474560-byte limit\nfatal error: stack overflow"
        if !strings.HasPrefix(output, want) {
                t.Fatalf("output does not start with %q:\n%s", want, output)
        }
 }
 
 func TestThreadExhaustion(t *testing.T) {
-       output := executeTest(t, threadExhaustionSource, nil)
+       output := runTestProg(t, "testprog", "ThreadExhaustion")
        want := "runtime: program exceeds 10-thread limit\nfatal error: thread exhaustion"
        if !strings.HasPrefix(output, want) {
                t.Fatalf("output does not start with %q:\n%s", want, output)
@@ -175,7 +197,7 @@ func TestThreadExhaustion(t *testing.T) {
 }
 
 func TestRecursivePanic(t *testing.T) {
-       output := executeTest(t, recursivePanicSource, nil)
+       output := runTestProg(t, "testprog", "RecursivePanic")
        want := `wrap: bad
 panic: again
 
@@ -187,7 +209,7 @@ panic: again
 }
 
 func TestGoexitCrash(t *testing.T) {
-       output := executeTest(t, goexitExitSource, nil)
+       output := runTestProg(t, "testprog", "GoexitExit")
        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)
@@ -211,15 +233,15 @@ func TestGoexitDefer(t *testing.T) {
 }
 
 func TestGoNil(t *testing.T) {
-       output := executeTest(t, goNilSource, nil)
+       output := runTestProg(t, "testprog", "GoNil")
        want := "go of nil func value"
        if !strings.Contains(output, want) {
                t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
        }
 }
 
-func TestMainGoroutineId(t *testing.T) {
-       output := executeTest(t, mainGoroutineIdSource, nil)
+func TestMainGoroutineID(t *testing.T) {
+       output := runTestProg(t, "testprog", "MainGoroutineID")
        want := "panic: test\n\ngoroutine 1 [running]:\n"
        if !strings.HasPrefix(output, want) {
                t.Fatalf("output does not start with %q:\n%s", want, output)
@@ -227,7 +249,7 @@ func TestMainGoroutineId(t *testing.T) {
 }
 
 func TestNoHelperGoroutines(t *testing.T) {
-       output := executeTest(t, noHelperGoroutinesSource, nil)
+       output := runTestProg(t, "testprog", "NoHelperGoroutines")
        matches := regexp.MustCompile(`goroutine [0-9]+ \[`).FindAllStringSubmatch(output, -1)
        if len(matches) != 1 || matches[0][0] != "goroutine 1 [" {
                t.Fatalf("want to see only goroutine 1, see:\n%s", output)
@@ -235,311 +257,39 @@ func TestNoHelperGoroutines(t *testing.T) {
 }
 
 func TestBreakpoint(t *testing.T) {
-       output := executeTest(t, breakpointSource, nil)
+       output := runTestProg(t, "testprog", "Breakpoint")
        want := "runtime.Breakpoint()"
        if !strings.Contains(output, want) {
                t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
        }
 }
 
-const crashSource = `
-package main
-
-import (
-       "fmt"
-       "runtime"
-)
-
-{{if .Cgo}}
-import "C"
-{{end}}
-
-func test(name string) {
-       defer func() {
-               if x := recover(); x != nil {
-                       fmt.Printf(" recovered")
-               }
-               fmt.Printf(" done\n")
-       }()
-       fmt.Printf("%s:", name)
-       var s *string
-       _ = *s
-       fmt.Print("SHOULD NOT BE HERE")
-}
-
-func testInNewThread(name string) {
-       c := make(chan bool)
-       go func() {
-               runtime.LockOSThread()
-               test(name)
-               c <- true
-       }()
-       <-c
-}
-
-func main() {
-       runtime.LockOSThread()
-       test("main")
-       testInNewThread("new-thread")
-       testInNewThread("second-new-thread")
-       test("main-again")
-}
-`
-
-const simpleDeadlockSource = `
-package main
-func main() {
-       select {}
-}
-`
-
-const initDeadlockSource = `
-package main
-func init() {
-       select {}
-}
-func main() {
-}
-`
-
-const lockedDeadlockSource = `
-package main
-import "runtime"
-func main() {
-       runtime.LockOSThread()
-       select {}
-}
-`
-
-const lockedDeadlockSource2 = `
-package main
-import (
-       "runtime"
-       "time"
-)
-func main() {
-       go func() {
-               runtime.LockOSThread()
-               select {}
-       }()
-       time.Sleep(time.Millisecond)
-       select {}
-}
-`
-
-const goexitDeadlockSource = `
-package main
-import (
-      "runtime"
-)
-
-func F() {
-      for i := 0; i < 10; i++ {
-      }
-}
-
-func main() {
-      go F()
-      go F()
-      runtime.Goexit()
-}
-`
-
-const stackOverflowSource = `
-package main
-
-import "runtime/debug"
-
-func main() {
-       debug.SetMaxStack(4<<20)
-       f(make([]byte, 10))
-}
-
-func f(x []byte) byte {
-       var buf [64<<10]byte
-       return x[0] + f(buf[:])
-}
-`
-
-const threadExhaustionSource = `
-package main
-
-import (
-       "runtime"
-       "runtime/debug"
-)
-
-func main() {
-       debug.SetMaxThreads(10)
-       c := make(chan int)
-       for i := 0; i < 100; i++ {
-               go func() {
-                       runtime.LockOSThread()
-                       c <- 0
-                       select{}
-               }()
-               <-c
-       }
-}
-`
-
-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{}
-}
-`
-
-const mainGoroutineIdSource = `
-package main
-func main() {
-       panic("test")
-}
-`
-
-const noHelperGoroutinesSource = `
-package main
-import (
-       "runtime"
-       "time"
-)
-func init() {
-       i := 0
-       runtime.SetFinalizer(&i, func(p *int) {})
-       time.AfterFunc(time.Hour, func() {})
-       panic("oops")
-}
-func main() {
-}
-`
-
-const breakpointSource = `
-package main
-import "runtime"
-func main() {
-       runtime.Breakpoint()
-}
-`
-
 func TestGoexitInPanic(t *testing.T) {
        // see issue 8774: this code used to trigger an infinite recursion
-       output := executeTest(t, goexitInPanicSource, nil)
+       output := runTestProg(t, "testprog", "GoexitInPanic")
        want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
        if !strings.HasPrefix(output, want) {
                t.Fatalf("output does not start with %q:\n%s", want, output)
        }
 }
 
-const goexitInPanicSource = `
-package main
-import "runtime"
-func main() {
-       go func() {
-               defer func() {
-                       runtime.Goexit()
-               }()
-               panic("hello")
-       }()
-       runtime.Goexit()
-}
-`
-
 func TestPanicAfterGoexit(t *testing.T) {
        // an uncaught panic should still work after goexit
-       output := executeTest(t, panicAfterGoexitSource, nil)
+       output := runTestProg(t, "testprog", "PanicAfterGoexit")
        want := "panic: hello"
        if !strings.HasPrefix(output, want) {
                t.Fatalf("output does not start with %q:\n%s", want, output)
        }
 }
 
-const panicAfterGoexitSource = `
-package main
-import "runtime"
-func main() {
-       defer func() {
-               panic("hello")
-       }()
-       runtime.Goexit()
-}
-`
-
 func TestRecoveredPanicAfterGoexit(t *testing.T) {
-       output := executeTest(t, recoveredPanicAfterGoexitSource, nil)
+       output := runTestProg(t, "testprog", "RecoveredPanicAfterGoexit")
        want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
        if !strings.HasPrefix(output, want) {
                t.Fatalf("output does not start with %q:\n%s", want, output)
        }
 }
 
-const recoveredPanicAfterGoexitSource = `
-package main
-import "runtime"
-func main() {
-       defer func() {
-               defer func() {
-                       r := recover()
-                       if r == nil {
-                               panic("bad recover")
-                       }
-               }()
-               panic("hello")
-       }()
-       runtime.Goexit()
-}
-`
-
 func TestRecoverBeforePanicAfterGoexit(t *testing.T) {
        // 1. defer a function that recovers
        // 2. defer a function that panics
@@ -561,29 +311,9 @@ func TestRecoverBeforePanicAfterGoexit(t *testing.T) {
 }
 
 func TestNetpollDeadlock(t *testing.T) {
-       output := executeTest(t, netpollDeadlockSource, nil)
+       output := runTestProg(t, "testprognet", "NetpollDeadlock")
        want := "done\n"
        if !strings.HasSuffix(output, want) {
                t.Fatalf("output does not start with %q:\n%s", want, output)
        }
 }
-
-const netpollDeadlockSource = `
-package main
-import (
-       "fmt"
-       "net"
-)
-func init() {
-       fmt.Println("dialing")
-       c, err := net.Dial("tcp", "localhost:14356")
-       if err == nil {
-               c.Close()
-       } else {
-               fmt.Println("error: ", err)
-       }
-}
-func main() {
-       fmt.Println("done")
-}
-`
index b925d028aaf34fcffc4fdfd228aaf89ae139f78f..5284a37b0f141721060c5e6a03098a4cd83c6f4c 100644 (file)
@@ -133,3 +133,33 @@ func loop(i int, c chan bool) {
        }
 }
 `
+
+func TestSignalExitStatus(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+       switch runtime.GOOS {
+       case "netbsd":
+               t.Skip("skipping on NetBSD; see https://golang.org/issue/14063")
+       }
+       exe, err := buildTestProg(t, "testprog")
+       if err != nil {
+               t.Fatal(err)
+       }
+       err = testEnv(exec.Command(exe, "SignalExitStatus")).Run()
+       if err == nil {
+               t.Error("test program succeeded unexpectedly")
+       } else if ee, ok := err.(*exec.ExitError); !ok {
+               t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err)
+       } else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
+               t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys())
+       } else if !ws.Signaled() || ws.Signal() != syscall.SIGTERM {
+               t.Errorf("got %v; expected SIGTERM", ee)
+       }
+}
+
+func TestSignalIgnoreSIGTRAP(t *testing.T) {
+       output := runTestProg(t, "testprognet", "SignalIgnoreSIGTRAP")
+       want := "OK\n"
+       if output != want {
+               t.Fatalf("want %s, got %s\n", want, output)
+       }
+}
index bcdde4b6a0b1869a7c492bf24777c9adef5f2300..0c915a2a768e9674f546d7d360ac2de306cfede5 100644 (file)
@@ -23,7 +23,11 @@ func UnlockOSThread()
 // This call will go away when the scheduler improves.
 func GOMAXPROCS(n int) int
 
-// NumCPU returns the number of logical CPUs on the local machine.
+// NumCPU returns the number of logical CPUs usable by the current process.
+//
+// The set of available CPUs is checked by querying the operating system
+// at process startup. Changes to operating system CPU allocation after
+// process startup are not reflected.
 func NumCPU() int
 
 // NumCgoCall returns the number of cgo calls made by the current process.
index c3363f9dd5835df09f618b34f3b6b8f74725d9a0..0f8a44c4c63e2db5197b20654a134bbb91d0d23e 100644 (file)
@@ -151,3 +151,14 @@ func SetPanicOnFault(enabled bool) bool
 // it to the given file descriptor.
 // The heap dump format is defined at https://golang.org/s/go13heapdump.
 func WriteHeapDump(fd uintptr)
+
+// SetTraceback sets the amount of detail printed by the runtime in
+// the traceback it prints before exiting due to an unrecovered panic
+// or an internal runtime error.
+// The level argument takes the same values as the GOTRACEBACK
+// environment variable. For example, SetTraceback("all") ensure
+// that the program prints all goroutines when it crashes.
+// See the package runtime documentation for details.
+// If SetTraceback is called with a level lower than that of the
+// environment variable, the call is ignored.
+func SetTraceback(level string)
index 13e1845098e4b842feca35accdffc8c493c5ba88..21bf6eb5582937449353db587de3670afef4ce35 100644 (file)
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package debug
+package debug_test
 
 import (
        "runtime"
+       . "runtime/debug"
        "testing"
        "time"
 )
@@ -75,7 +76,7 @@ func TestReadGCStats(t *testing.T) {
 var big = make([]byte, 1<<20)
 
 func TestFreeOSMemory(t *testing.T) {
-       if runtime.GOARCH == "arm64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" ||
+       if runtime.GOARCH == "arm64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "mips64" || runtime.GOARCH == "mips64le" ||
                runtime.GOOS == "nacl" {
                t.Skip("issue 9993; scavenger temporarily disabled on systems with physical pages larger than logical pages")
        }
index cb2f2f06798a4882144912696f9a246aac79ce48..5761c015b8e28676565aabdd805b3eb722ba432f 100644 (file)
@@ -2,12 +2,13 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package debug
+package debug_test
 
 import (
        "io/ioutil"
        "os"
        "runtime"
+       . "runtime/debug"
        "testing"
 )
 
index ab12bffa6e5da817339149928101b4fb6f88ddbd..5d810af5407c304ebf6015cc7bfe338d486a8963 100644 (file)
@@ -7,92 +7,24 @@
 package debug
 
 import (
-       "bytes"
-       "fmt"
-       "io/ioutil"
        "os"
        "runtime"
 )
 
-var (
-       dunno     = []byte("???")
-       centerDot = []byte("·")
-       dot       = []byte(".")
-       slash     = []byte("/")
-)
-
-// PrintStack prints to standard error the stack trace returned by Stack.
+// PrintStack prints to standard error the stack trace returned by runtime.Stack.
 func PrintStack() {
-       os.Stderr.Write(stack())
+       os.Stderr.Write(Stack())
 }
 
 // Stack returns a formatted stack trace of the goroutine that calls it.
-// For each routine, it includes the source line information and PC value,
-// then attempts to discover, for Go functions, the calling function or
-// method and the text of the line containing the invocation.
-//
-// Deprecated: Use package runtime's Stack instead.
+// It calls runtime.Stack with a large enough buffer to capture the entire trace.
 func Stack() []byte {
-       return stack()
-}
-
-// stack implements Stack, skipping 2 frames
-func stack() []byte {
-       buf := new(bytes.Buffer) // the returned data
-       // As we loop, we open files and read them. These variables record the currently
-       // loaded file.
-       var lines [][]byte
-       var lastFile string
-       for i := 2; ; i++ { // Caller we care about is the user, 2 frames up
-               pc, file, line, ok := runtime.Caller(i)
-               if !ok {
-                       break
+       buf := make([]byte, 1024)
+       for {
+               n := runtime.Stack(buf, false)
+               if n < len(buf) {
+                       return buf[:n]
                }
-               // Print this much at least.  If we can't find the source, it won't show.
-               fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
-               if file != lastFile {
-                       data, err := ioutil.ReadFile(file)
-                       if err != nil {
-                               continue
-                       }
-                       lines = bytes.Split(data, []byte{'\n'})
-                       lastFile = file
-               }
-               line-- // in stack trace, lines are 1-indexed but our array is 0-indexed
-               fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line))
-       }
-       return buf.Bytes()
-}
-
-// source returns a space-trimmed slice of the n'th line.
-func source(lines [][]byte, n int) []byte {
-       if n < 0 || n >= len(lines) {
-               return dunno
-       }
-       return bytes.Trim(lines[n], " \t")
-}
-
-// function returns, if possible, the name of the function containing the PC.
-func function(pc uintptr) []byte {
-       fn := runtime.FuncForPC(pc)
-       if fn == nil {
-               return dunno
-       }
-       name := []byte(fn.Name())
-       // The name includes the path name to the package, which is unnecessary
-       // since the file name is already included.  Plus, it has center dots.
-       // That is, we see
-       //      runtime/debug.*T·ptrmethod
-       // and want
-       //      *T.ptrmethod
-       // Since the package path might contains dots (e.g. code.google.com/...),
-       // we first remove the path prefix if there is one.
-       if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 {
-               name = name[lastslash+1:]
-       }
-       if period := bytes.Index(name, dot); period >= 0 {
-               name = name[period+1:]
+               buf = make([]byte, 2*len(buf))
        }
-       name = bytes.Replace(name, centerDot, dot, -1)
-       return name
 }
index 263d715599725c10d7a25a11400b7cbfa6147679..0f769ee6cab353cc3b0779b8c2a501a6cbee0075 100644 (file)
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package debug
+package debug_test
 
 import (
+       . "runtime/debug"
        "strings"
        "testing"
 )
@@ -22,16 +23,19 @@ func (t T) method() []byte {
        The traceback should look something like this, modulo line numbers and hex constants.
        Don't worry much about the base levels, but check the ones in our own package.
 
-               /Users/r/go/src/pkg/runtime/debug/stack_test.go:15 (0x13878)
-                       (*T).ptrmethod: return Stack()
-               /Users/r/go/src/pkg/runtime/debug/stack_test.go:18 (0x138dd)
-                       T.method: return t.ptrmethod()
-               /Users/r/go/src/pkg/runtime/debug/stack_test.go:23 (0x13920)
-                       TestStack: b := T(0).method()
-               /Users/r/go/src/pkg/testing/testing.go:132 (0x14a7a)
-                       tRunner: test.F(t)
-               /Users/r/go/src/pkg/runtime/proc.c:145 (0xc970)
-                       ???: runtime·unlock(&runtime·sched);
+               goroutine 10 [running]:
+               runtime/debug.Stack(0x0, 0x0, 0x0)
+                       /Users/r/go/src/runtime/debug/stack.go:28 +0x80
+               runtime/debug.(*T).ptrmethod(0xc82005ee70, 0x0, 0x0, 0x0)
+                       /Users/r/go/src/runtime/debug/stack_test.go:15 +0x29
+               runtime/debug.T.method(0x0, 0x0, 0x0, 0x0)
+                       /Users/r/go/src/runtime/debug/stack_test.go:18 +0x32
+               runtime/debug.TestStack(0xc8201ce000)
+                       /Users/r/go/src/runtime/debug/stack_test.go:37 +0x38
+               testing.tRunner(0xc8201ce000, 0x664b58)
+                       /Users/r/go/src/testing/testing.go:456 +0x98
+               created by testing.RunTests
+                       /Users/r/go/src/testing/testing.go:561 +0x86d
 */
 func TestStack(t *testing.T) {
        b := T(0).method()
@@ -41,13 +45,10 @@ func TestStack(t *testing.T) {
        }
        n := 0
        frame := func(line, code string) {
+               check(t, lines[n], code)
+               n++
                check(t, lines[n], line)
                n++
-               // The source might not be available while running the test.
-               if strings.HasPrefix(lines[n], "\t") {
-                       check(t, lines[n], code)
-                       n++
-               }
        }
        frame("stack_test.go", "\tmethod.N15_runtime_debug.T: return Stack()")
        frame("stack_test.go", "\tmethod.N15_runtime_debug.T: return t.ptrmethod()")
diff --git a/libgo/go/runtime/defs_linux_mips64x.go b/libgo/go/runtime/defs_linux_mips64x.go
new file mode 100644 (file)
index 0000000..bb3cd98
--- /dev/null
@@ -0,0 +1,183 @@
+// +build mips64 mips64le
+// +build linux
+
+package runtime
+
+const (
+       _EINTR  = 0x4
+       _EAGAIN = 0xb
+       _ENOMEM = 0xc
+
+       _PROT_NONE  = 0x0
+       _PROT_READ  = 0x1
+       _PROT_WRITE = 0x2
+       _PROT_EXEC  = 0x4
+
+       _MAP_ANON    = 0x800
+       _MAP_PRIVATE = 0x2
+       _MAP_FIXED   = 0x10
+
+       _MADV_DONTNEED   = 0x4
+       _MADV_HUGEPAGE   = 0xe
+       _MADV_NOHUGEPAGE = 0xf
+
+       _SA_RESTART = 0x10000000
+       _SA_ONSTACK = 0x8000000
+       _SA_SIGINFO = 0x8
+
+       _SIGHUP    = 0x1
+       _SIGINT    = 0x2
+       _SIGQUIT   = 0x3
+       _SIGILL    = 0x4
+       _SIGTRAP   = 0x5
+       _SIGABRT   = 0x6
+       _SIGEMT    = 0x7
+       _SIGFPE    = 0x8
+       _SIGKILL   = 0x9
+       _SIGBUS    = 0xa
+       _SIGSEGV   = 0xb
+       _SIGSYS    = 0xc
+       _SIGPIPE   = 0xd
+       _SIGALRM   = 0xe
+       _SIGUSR1   = 0x10
+       _SIGUSR2   = 0x11
+       _SIGCHLD   = 0x12
+       _SIGPWR    = 0x13
+       _SIGWINCH  = 0x14
+       _SIGURG    = 0x15
+       _SIGIO     = 0x16
+       _SIGSTOP   = 0x17
+       _SIGTSTP   = 0x18
+       _SIGCONT   = 0x19
+       _SIGTTIN   = 0x1a
+       _SIGTTOU   = 0x1b
+       _SIGVTALRM = 0x1c
+       _SIGPROF   = 0x1d
+       _SIGXCPU   = 0x1e
+       _SIGXFSZ   = 0x1f
+
+       _FPE_INTDIV = 0x1
+       _FPE_INTOVF = 0x2
+       _FPE_FLTDIV = 0x3
+       _FPE_FLTOVF = 0x4
+       _FPE_FLTUND = 0x5
+       _FPE_FLTRES = 0x6
+       _FPE_FLTINV = 0x7
+       _FPE_FLTSUB = 0x8
+
+       _BUS_ADRALN = 0x1
+       _BUS_ADRERR = 0x2
+       _BUS_OBJERR = 0x3
+
+       _SEGV_MAPERR = 0x1
+       _SEGV_ACCERR = 0x2
+
+       _ITIMER_REAL    = 0x0
+       _ITIMER_VIRTUAL = 0x1
+       _ITIMER_PROF    = 0x2
+
+       _EPOLLIN       = 0x1
+       _EPOLLOUT      = 0x4
+       _EPOLLERR      = 0x8
+       _EPOLLHUP      = 0x10
+       _EPOLLRDHUP    = 0x2000
+       _EPOLLET       = 0x80000000
+       _EPOLL_CLOEXEC = 0x80000
+       _EPOLL_CTL_ADD = 0x1
+       _EPOLL_CTL_DEL = 0x2
+       _EPOLL_CTL_MOD = 0x3
+)
+
+//struct Sigset {
+//     uint64  sig[1];
+//};
+//typedef uint64 Sigset;
+
+type timespec struct {
+       tv_sec  int64
+       tv_nsec int64
+}
+
+func (ts *timespec) set_sec(x int64) {
+       ts.tv_sec = x
+}
+
+func (ts *timespec) set_nsec(x int32) {
+       ts.tv_nsec = int64(x)
+}
+
+type timeval struct {
+       tv_sec  int64
+       tv_usec int64
+}
+
+func (tv *timeval) set_usec(x int32) {
+       tv.tv_usec = int64(x)
+}
+
+type sigactiont struct {
+       sa_flags   uint32
+       sa_handler uintptr
+       sa_mask    [2]uint64
+       // linux header does not have sa_restorer field,
+       // but it is used in setsig(). it is no harm to put it here
+       sa_restorer uintptr
+}
+
+type siginfo struct {
+       si_signo int32
+       si_code  int32
+       si_errno int32
+       __pad0   [1]int32
+       // below here is a union; si_addr is the only field we use
+       si_addr uint64
+}
+
+type itimerval struct {
+       it_interval timeval
+       it_value    timeval
+}
+
+type epollevent struct {
+       events    uint32
+       pad_cgo_0 [4]byte
+       data      [8]byte // unaligned uintptr
+}
+
+const (
+       _O_RDONLY    = 0x0
+       _O_CLOEXEC   = 0x80000
+       _SA_RESTORER = 0
+)
+
+type sigaltstackt struct {
+       ss_sp    *byte
+       ss_size  uintptr
+       ss_flags int32
+}
+
+type sigcontext struct {
+       sc_regs      [32]uint64
+       sc_fpregs    [32]uint64
+       sc_mdhi      uint64
+       sc_hi1       uint64
+       sc_hi2       uint64
+       sc_hi3       uint64
+       sc_mdlo      uint64
+       sc_lo1       uint64
+       sc_lo2       uint64
+       sc_lo3       uint64
+       sc_pc        uint64
+       sc_fpc_csr   uint32
+       sc_used_math uint32
+       sc_dsp       uint32
+       sc_reserved  uint32
+}
+
+type ucontext struct {
+       uc_flags    uint64
+       uc_link     *ucontext
+       uc_stack    sigaltstackt
+       uc_mcontext sigcontext
+       uc_sigmask  uint64
+}
index 8782914b5b98375c666c4ca32cd06ee3606560e2..fd328a1d363091edab8b7edbac7a63d42abd3fc6 100644 (file)
@@ -6,7 +6,9 @@
 
 package runtime
 
-import "unsafe"
+import (
+       "unsafe"
+)
 
 //var Fadd64 = fadd64
 //var Fsub64 = fsub64
@@ -135,22 +137,22 @@ func setenvs([]string)
 var Envs = envs
 var SetEnvs = setenvs
 
-//var BigEndian = _BigEndian
+//var BigEndian = sys.BigEndian
 
 // For benchmarking.
 
 /*
 func BenchSetType(n int, x interface{}) {
-       e := *(*eface)(unsafe.Pointer(&x))
+       e := *efaceOf(&x)
        t := e._type
        var size uintptr
        var p unsafe.Pointer
        switch t.kind & kindMask {
-       case _KindPtr:
+       case kindPtr:
                t = (*ptrtype)(unsafe.Pointer(t)).elem
                size = t.size
                p = e.data
-       case _KindSlice:
+       case kindSlice:
                slice := *(*struct {
                        ptr      unsafe.Pointer
                        len, cap uintptr
@@ -167,8 +169,15 @@ func BenchSetType(n int, x interface{}) {
        })
 }
 
-const PtrSize = ptrSize
+const PtrSize = sys.PtrSize
 
 var TestingAssertE2I2GC = &testingAssertE2I2GC
 var TestingAssertE2T2GC = &testingAssertE2T2GC
+
+var ForceGCPeriod = &forcegcperiod
 */
+
+// SetTracebackEnv is like runtime/debug.SetTraceback, but it raises
+// the "environment" traceback level, so later calls to
+// debug.SetTraceback (e.g., from testing timeouts) can't lower it.
+func SetTracebackEnv(level string)
index 61fcef9c0f6ee9bd308f904e56da48bf166bd216..f712c6f65353c60df57708949c369f7399055ab4 100644 (file)
@@ -6,4 +6,12 @@
 
 package runtime
 
+import "unsafe"
+
 var TestingWER = &testingWER
+
+func NumberOfProcessors() int32 {
+       var info systeminfo
+       stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
+       return int32(info.dwnumberofprocessors)
+}
index 6301d0173b26c03b32c81a1e91f1cd53ace8c9e9..eca54a751459accef8499e0d57019d27ebb872e1 100644 (file)
@@ -27,6 +27,13 @@ It is a comma-separated list of name=val pairs setting these named variables:
        allocfreetrace: setting allocfreetrace=1 causes every allocation to be
        profiled and a stack trace printed on each object's allocation and free.
 
+       cgocheck: setting cgocheck=0 disables all checks for packages
+       using cgo to incorrectly pass Go pointers to non-Go code.
+       Setting cgocheck=1 (the default) enables relatively cheap
+       checks that may miss some errors.  Setting cgocheck=2 enables
+       expensive checks that should not miss any errors, but will
+       cause your program to run slower.
+
        efence: setting efence=1 causes the allocator to run in a mode
        where each object is allocated on a unique page and addresses are
        never recycled.
@@ -59,7 +66,7 @@ It is a comma-separated list of name=val pairs setting these named variables:
        length of the pause. Setting gctrace=2 emits the same summary but also
        repeats each collection. The format of this line is subject to change.
        Currently, it is:
-               gc # @#s #%: #+...+# ms clock, #+...+# ms cpu, #->#-># MB, # MB goal, # P
+               gc # @#s #%: #+#+# ms clock, #+#/#/#+# ms cpu, #->#-># MB, # MB goal, # P
        where the fields are as follows:
                gc #        the GC number, incremented at each GC
                @#s         time in seconds since program start
@@ -68,9 +75,9 @@ It is a comma-separated list of name=val pairs setting these named variables:
                #->#-># MB  heap size at GC start, at GC end, and live heap
                # MB goal   goal heap size
                # P         number of processors used
-       The phases are stop-the-world (STW) sweep termination, scan,
-       synchronize Ps, mark, and STW mark termination. The CPU times
-       for mark are broken down in to assist time (GC performed in
+       The phases are stop-the-world (STW) sweep termination, concurrent
+       mark and scan, and STW mark termination. The CPU times
+       for mark/scan are broken down in to assist time (GC performed in
        line with allocation), background GC time, and idle GC time.
        If the line ends with "(forced)", this GC was forced by a
        runtime.GC() call and all phases are STW.
@@ -96,6 +103,9 @@ It is a comma-separated list of name=val pairs setting these named variables:
        schedtrace: setting schedtrace=X causes the scheduler to emit a single line to standard
        error every X milliseconds, summarizing the scheduler state.
 
+The net and net/http packages also refer to debugging variables in GODEBUG.
+See the documentation for those packages for details.
+
 The GOMAXPROCS variable limits the number of operating system threads that
 can execute user-level Go code simultaneously. There is no limit to the number of threads
 that can be blocked in system calls on behalf of Go code; those do not count against
@@ -104,15 +114,24 @@ the limit.
 
 The GOTRACEBACK variable controls the amount of output generated when a Go
 program fails due to an unrecovered panic or an unexpected runtime condition.
-By default, a failure prints a stack trace for every extant goroutine, eliding functions
-internal to the run-time system, and then exits with exit code 2.
-If GOTRACEBACK=0, the per-goroutine stack traces are omitted entirely.
-If GOTRACEBACK=1, the default behavior is used.
-If GOTRACEBACK=2, the per-goroutine stack traces include run-time functions.
-If GOTRACEBACK=crash, the per-goroutine stack traces include run-time functions,
-and if possible the program crashes in an operating-specific manner instead of
-exiting. For example, on Unix systems, the program raises SIGABRT to trigger a
-core dump.
+By default, a failure prints a stack trace for the current goroutine,
+eliding functions internal to the run-time system, and then exits with exit code 2.
+The failure prints stack traces for all goroutines if there is no current goroutine
+or the failure is internal to the run-time.
+GOTRACEBACK=none omits the goroutine stack traces entirely.
+GOTRACEBACK=single (the default) behaves as described above.
+GOTRACEBACK=all adds stack traces for all user-created goroutines.
+GOTRACEBACK=system is like ``all'' but adds stack frames for run-time functions
+and shows goroutines created internally by the run-time.
+GOTRACEBACK=crash is like ``system'' but crashes in an operating system-specific
+manner instead of exiting. For example, on Unix systems, the crash raises
+SIGABRT to trigger a core dump.
+For historical reasons, the GOTRACEBACK settings 0, 1, and 2 are synonyms for
+none, all, and system, respectively.
+The runtime/debug package's SetTraceback function allows increasing the
+amount of output at run time, but it cannot reduce the amount below that
+specified by the environment variable.
+See https://golang.org/pkg/runtime/debug/#SetTraceback.
 
 The GOARCH, GOOS, GOPATH, and GOROOT environment variables complete
 the set of Go environment variables. They influence the building of Go programs
diff --git a/libgo/go/runtime/fastlog2.go b/libgo/go/runtime/fastlog2.go
new file mode 100644 (file)
index 0000000..b22e825
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2015 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 runtime
+
+import "unsafe"
+
+// fastlog2 implements a fast approximation to the base 2 log of a
+// float64. This is used to compute a geometric distribution for heap
+// sampling, without introducing dependences into package math. This
+// uses a very rough approximation using the float64 exponent and the
+// first 25 bits of the mantissa. The top 5 bits of the mantissa are
+// used to load limits from a table of constants and the rest are used
+// to scale linearly between them.
+func fastlog2(x float64) float64 {
+       const fastlogScaleBits = 20
+       const fastlogScaleRatio = 1.0 / (1 << fastlogScaleBits)
+
+       xBits := float64bits(x)
+       // Extract the exponent from the IEEE float64, and index a constant
+       // table with the first 10 bits from the mantissa.
+       xExp := int64((xBits>>52)&0x7FF) - 1023
+       xManIndex := (xBits >> (52 - fastlogNumBits)) % (1 << fastlogNumBits)
+       xManScale := (xBits >> (52 - fastlogNumBits - fastlogScaleBits)) % (1 << fastlogScaleBits)
+
+       low, high := fastlog2Table[xManIndex], fastlog2Table[xManIndex+1]
+       return float64(xExp) + low + (high-low)*float64(xManScale)*fastlogScaleRatio
+}
+
+// float64bits returns the IEEE 754 binary representation of f.
+// Taken from math.Float64bits to avoid dependences into package math.
+func float64bits(f float64) uint64 { return *(*uint64)(unsafe.Pointer(&f)) }
diff --git a/libgo/go/runtime/fastlog2_test.go b/libgo/go/runtime/fastlog2_test.go
new file mode 100644 (file)
index 0000000..8f92dc6
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2015 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 ignore
+
+package runtime_test
+
+import (
+       "math"
+       "runtime"
+       "testing"
+)
+
+func TestFastLog2(t *testing.T) {
+       // Compute the euclidean distance between math.Log2 and the FastLog2
+       // implementation over the range of interest for heap sampling.
+       const randomBitCount = 26
+       var e float64
+
+       inc := 1
+       if testing.Short() {
+               // Check 1K total values, down from 64M.
+               inc = 1 << 16
+       }
+       for i := 1; i < 1<<randomBitCount; i += inc {
+               l, fl := math.Log2(float64(i)), runtime.Fastlog2(float64(i))
+               d := l - fl
+               e += d * d
+       }
+       e = math.Sqrt(e)
+
+       if e > 1.0 {
+               t.Fatalf("imprecision on fastlog2 implementation, want <=1.0, got %f", e)
+       }
+}
diff --git a/libgo/go/runtime/fastlog2table.go b/libgo/go/runtime/fastlog2table.go
new file mode 100644 (file)
index 0000000..c36d583
--- /dev/null
@@ -0,0 +1,43 @@
+// AUTO-GENERATED by mkfastlog2table.go
+// Run go generate from src/runtime to update.
+// See mkfastlog2table.go for comments.
+
+package runtime
+
+const fastlogNumBits = 5
+
+var fastlog2Table = [1<<fastlogNumBits + 1]float64{
+       0,
+       0.0443941193584535,
+       0.08746284125033943,
+       0.12928301694496647,
+       0.16992500144231248,
+       0.2094533656289499,
+       0.24792751344358555,
+       0.28540221886224837,
+       0.3219280948873623,
+       0.3575520046180837,
+       0.39231742277876036,
+       0.4262647547020979,
+       0.4594316186372973,
+       0.4918530963296748,
+       0.5235619560570128,
+       0.5545888516776374,
+       0.5849625007211563,
+       0.6147098441152082,
+       0.6438561897747247,
+       0.6724253419714956,
+       0.7004397181410922,
+       0.7279204545631992,
+       0.7548875021634686,
+       0.7813597135246596,
+       0.8073549220576042,
+       0.8328900141647417,
+       0.8579809951275721,
+       0.8826430493618412,
+       0.9068905956085185,
+       0.9307373375628862,
+       0.9541963103868752,
+       0.9772799234999164,
+       1,
+}
index 2a95cc70e84865da9d60200d6557b6bb4e206018..71d46561e0395cb22df8c684ef9612788d728e98 100644 (file)
@@ -18,59 +18,13 @@ func TestGcSys(t *testing.T) {
        if os.Getenv("GOGC") == "off" {
                t.Skip("skipping test; GOGC=off in environment")
        }
-       data := struct{ Short bool }{testing.Short()}
-       got := executeTest(t, testGCSysSource, &data)
+       got := runTestProg(t, "testprog", "GCSys")
        want := "OK\n"
        if got != want {
                t.Fatalf("expected %q, but got %q", want, got)
        }
 }
 
-const testGCSysSource = `
-package main
-
-import (
-       "fmt"
-       "runtime"
-)
-
-func main() {
-       runtime.GOMAXPROCS(1)
-       memstats := new(runtime.MemStats)
-       runtime.GC()
-       runtime.ReadMemStats(memstats)
-       sys := memstats.Sys
-
-       runtime.MemProfileRate = 0 // disable profiler
-
-       itercount := 1000000
-{{if .Short}}
-       itercount = 100000
-{{end}}
-       for i := 0; i < itercount; i++ {
-               workthegc()
-       }
-
-       // Should only be using a few MB.
-       // We allocated 100 MB or (if not short) 1 GB.
-       runtime.ReadMemStats(memstats)
-       if sys > memstats.Sys {
-               sys = 0
-       } else {
-               sys = memstats.Sys - sys
-       }
-       if sys > 16<<20 {
-               fmt.Printf("using too much memory: %d bytes\n", sys)
-               return
-       }
-       fmt.Printf("OK\n")
-}
-
-func workthegc() []byte {
-       return make([]byte, 1029)
-}
-`
-
 func TestGcDeepNesting(t *testing.T) {
        type T [2][2][2][2][2][2][2][2][2][2]*int
        a := new(T)
@@ -198,6 +152,39 @@ func TestHugeGCInfo(t *testing.T) {
        }
 }
 
+/*
+func TestPeriodicGC(t *testing.T) {
+       // Make sure we're not in the middle of a GC.
+       runtime.GC()
+
+       var ms1, ms2 runtime.MemStats
+       runtime.ReadMemStats(&ms1)
+
+       // Make periodic GC run continuously.
+       orig := *runtime.ForceGCPeriod
+       *runtime.ForceGCPeriod = 0
+
+       // Let some periodic GCs happen. In a heavily loaded system,
+       // it's possible these will be delayed, so this is designed to
+       // succeed quickly if things are working, but to give it some
+       // slack if things are slow.
+       var numGCs uint32
+       const want = 2
+       for i := 0; i < 20 && numGCs < want; i++ {
+               time.Sleep(5 * time.Millisecond)
+
+               // Test that periodic GC actually happened.
+               runtime.ReadMemStats(&ms2)
+               numGCs = ms2.NumGC - ms1.NumGC
+       }
+       *runtime.ForceGCPeriod = orig
+
+       if numGCs < want {
+               t.Fatalf("no periodic GC: got %v GCs, want >= 2", numGCs)
+       }
+}
+*/
+
 func BenchmarkSetTypePtr(b *testing.B) {
        benchSetType(b, new(*byte))
 }
@@ -481,10 +468,12 @@ func TestAssertE2T2Liveness(t *testing.T) {
        testIfaceEqual(io.EOF)
 }
 
+var a bool
+
+//go:noinline
 func testIfaceEqual(x interface{}) {
        if x == "abc" {
-               // Prevent inlining
-               panic("")
+               a = true
        }
 }
 
index 7e345e55a4cf7034d90a40dfaa96d14287d4472a..d3262a656c5085f6870728c080e9ca73ed2c678e 100644 (file)
@@ -130,7 +130,7 @@ func infoBigStruct() []byte {
                        typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
                        typePointer, typeScalar, // i string
                }
-       case "arm64", "amd64", "ppc64", "ppc64le":
+       case "arm64", "amd64", "mips64", "mips64le", "ppc64", "ppc64le":
                return []byte{
                        typePointer,                        // q *int
                        typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
diff --git a/libgo/go/runtime/lfstack_linux_mips64x.go b/libgo/go/runtime/lfstack_linux_mips64x.go
new file mode 100644 (file)
index 0000000..49b6558
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2015 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 mips64 mips64le
+// +build linux
+
+package runtime
+
+import "unsafe"
+
+// On mips64, Linux limits the user address space to 40 bits (see
+// TASK_SIZE64 in the Linux kernel).  This has grown over time,
+// so here we allow 48 bit addresses.
+//
+// In addition to the 16 bits taken from the top, we can take 3 from the
+// bottom, because node must be pointer-aligned, giving a total of 19 bits
+// of count.
+const (
+       addrBits = 48
+       cntBits  = 64 - addrBits + 3
+)
+
+func lfstackPack(node *lfnode, cnt uintptr) uint64 {
+       return uint64(uintptr(unsafe.Pointer(node)))<<(64-addrBits) | uint64(cnt&(1<<cntBits-1))
+}
+
+func lfstackUnpack(val uint64) (node *lfnode, cnt uintptr) {
+       node = (*lfnode)(unsafe.Pointer(uintptr(val >> cntBits << 3)))
+       cnt = uintptr(val & (1<<cntBits - 1))
+       return
+}
index df6a0e5246cc6e5d13101f41d809b041eca72c9d..4f9262760e1bc39e5427db215e70fa1d8596f871 100644 (file)
@@ -18,13 +18,14 @@ func TestMemStats(t *testing.T) {
        st := new(MemStats)
        ReadMemStats(st)
 
-       // Everything except HeapReleased and HeapIdle, because they indeed can be 0.
+       // Everything except HeapReleased, HeapIdle, and NumGC,
+       // because they indeed can be 0.
        if st.Alloc == 0 || st.TotalAlloc == 0 || st.Sys == 0 || st.Lookups == 0 ||
                st.Mallocs == 0 || st.Frees == 0 || st.HeapAlloc == 0 || st.HeapSys == 0 ||
                st.HeapInuse == 0 || st.HeapObjects == 0 || st.StackInuse == 0 ||
                st.StackSys == 0 || st.MSpanInuse == 0 || st.MSpanSys == 0 || st.MCacheInuse == 0 ||
                st.MCacheSys == 0 || st.BuckHashSys == 0 || st.GCSys == 0 || st.OtherSys == 0 ||
-               st.NextGC == 0 || st.NumGC == 0 {
+               st.NextGC == 0 {
                t.Fatalf("Zero value: %+v", *st)
        }
 
@@ -58,6 +59,14 @@ func TestMemStats(t *testing.T) {
                if st.PauseTotalNs != pauseTotal {
                        t.Fatalf("PauseTotalNs(%d) != sum PauseNs(%d)", st.PauseTotalNs, pauseTotal)
                }
+               for i := int(st.NumGC); i < len(st.PauseNs); i++ {
+                       if st.PauseNs[i] != 0 {
+                               t.Fatalf("Non-zero PauseNs[%d]: %+v", i, st)
+                       }
+                       if st.PauseEnd[i] != 0 {
+                               t.Fatalf("Non-zero PauseEnd[%d]: %+v", i, st)
+                       }
+               }
        } else {
                if st.PauseTotalNs < pauseTotal {
                        t.Fatalf("PauseTotalNs(%d) < sum PauseNs(%d)", st.PauseTotalNs, pauseTotal)
@@ -83,6 +92,23 @@ func TestStringConcatenationAllocs(t *testing.T) {
        }
 }
 
+func TestTinyAlloc(t *testing.T) {
+       const N = 16
+       var v [N]unsafe.Pointer
+       for i := range v {
+               v[i] = unsafe.Pointer(new(byte))
+       }
+
+       chunks := make(map[uintptr]bool, N)
+       for _, p := range v {
+               chunks[uintptr(p)&^7] = true
+       }
+
+       if len(chunks) == N {
+               t.Fatal("no bytes allocated within the same 8-byte chunk")
+       }
+}
+
 var mallocSink uintptr
 
 func BenchmarkMalloc8(b *testing.B) {
diff --git a/libgo/go/runtime/mkfastlog2table.go b/libgo/go/runtime/mkfastlog2table.go
new file mode 100644 (file)
index 0000000..587ebf4
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright 2015 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 ignore
+
+// fastlog2Table contains log2 approximations for 5 binary digits.
+// This is used to implement fastlog2, which is used for heap sampling.
+
+package main
+
+import (
+       "bytes"
+       "fmt"
+       "io/ioutil"
+       "log"
+       "math"
+)
+
+func main() {
+       var buf bytes.Buffer
+
+       fmt.Fprintln(&buf, "// AUTO-GENERATED by mkfastlog2table.go")
+       fmt.Fprintln(&buf, "// Run go generate from src/runtime to update.")
+       fmt.Fprintln(&buf, "// See mkfastlog2table.go for comments.")
+       fmt.Fprintln(&buf)
+       fmt.Fprintln(&buf, "package runtime")
+       fmt.Fprintln(&buf)
+       fmt.Fprintln(&buf, "const fastlogNumBits =", fastlogNumBits)
+       fmt.Fprintln(&buf)
+
+       fmt.Fprintln(&buf, "var fastlog2Table = [1<<fastlogNumBits + 1]float64{")
+       table := computeTable()
+       for _, t := range table {
+               fmt.Fprintf(&buf, "\t%v,\n", t)
+       }
+       fmt.Fprintln(&buf, "}")
+
+       if err := ioutil.WriteFile("fastlog2table.go", buf.Bytes(), 0644); err != nil {
+               log.Fatalln(err)
+       }
+}
+
+const fastlogNumBits = 5
+
+func computeTable() []float64 {
+       fastlog2Table := make([]float64, 1<<fastlogNumBits+1)
+       for i := 0; i <= (1 << fastlogNumBits); i++ {
+               fastlog2Table[i] = math.Log2(1.0 + float64(i)/(1<<fastlogNumBits))
+       }
+       return fastlog2Table
+}
diff --git a/libgo/go/runtime/mmap.go b/libgo/go/runtime/mmap.go
new file mode 100644 (file)
index 0000000..a076842
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2015 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 !plan9
+// +build !solaris
+// +build !windows
+// +build !nacl
+// +build !linux !amd64
+
+package runtime
+
+import "unsafe"
+
+// mmap calls the mmap system call.  It is implemented in assembly.
+func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
diff --git a/libgo/go/runtime/msan.go b/libgo/go/runtime/msan.go
new file mode 100644 (file)
index 0000000..4dbdf05
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright 2015 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 msan
+
+package runtime
+
+import (
+       "unsafe"
+)
+
+// Public memory sanitizer API.
+
+func MSanRead(addr unsafe.Pointer, len int) {
+       msanread(addr, uintptr(len))
+}
+
+func MSanWrite(addr unsafe.Pointer, len int) {
+       msanwrite(addr, uintptr(len))
+}
+
+// Private interface for the runtime.
+const msanenabled = true
+
+// If we are running on the system stack, the C program may have
+// marked part of that stack as uninitialized.  We don't instrument
+// the runtime, but operations like a slice copy can call msanread
+// anyhow for values on the stack.  Just ignore msanread when running
+// on the system stack.  The other msan functions are fine.
+func msanread(addr unsafe.Pointer, sz uintptr) {
+       g := getg()
+       if g == g.m.g0 || g == g.m.gsignal {
+               return
+       }
+       domsanread(addr, sz)
+}
+
+//go:noescape
+func domsanread(addr unsafe.Pointer, sz uintptr)
+
+//go:noescape
+func msanwrite(addr unsafe.Pointer, sz uintptr)
+
+//go:noescape
+func msanmalloc(addr unsafe.Pointer, sz uintptr)
+
+//go:noescape
+func msanfree(addr unsafe.Pointer, sz uintptr)
+
+// These are called from msan_amd64.s
+//go:cgo_import_static __msan_read_go
+//go:cgo_import_static __msan_write_go
+//go:cgo_import_static __msan_malloc_go
+//go:cgo_import_static __msan_free_go
diff --git a/libgo/go/runtime/msan/msan.go b/libgo/go/runtime/msan/msan.go
new file mode 100644 (file)
index 0000000..b6ea3f0
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2015 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 msan,linux,amd64
+
+package msan
+
+/*
+#cgo CFLAGS: -fsanitize=memory
+#cgo LDFLAGS: -fsanitize=memory
+
+#include <stdint.h>
+#include <sanitizer/msan_interface.h>
+
+void __msan_read_go(void *addr, uintptr_t sz) {
+       __msan_check_mem_is_initialized(addr, sz);
+}
+
+void __msan_write_go(void *addr, uintptr_t sz) {
+       __msan_unpoison(addr, sz);
+}
+
+void __msan_malloc_go(void *addr, uintptr_t sz) {
+       __msan_unpoison(addr, sz);
+}
+
+void __msan_free_go(void *addr, uintptr_t sz) {
+       __msan_poison(addr, sz);
+}
+*/
+import "C"
diff --git a/libgo/go/runtime/msan0.go b/libgo/go/runtime/msan0.go
new file mode 100644 (file)
index 0000000..e206720
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2015 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 !msan
+
+// Dummy MSan support API, used when not built with -msan.
+
+package runtime
+
+import (
+       "unsafe"
+)
+
+const msanenabled = false
+
+// Because msanenabled is false, none of these functions should be called.
+
+func msanread(addr unsafe.Pointer, sz uintptr)   { throw("msan") }
+func msanwrite(addr unsafe.Pointer, sz uintptr)  { throw("msan") }
+func msanmalloc(addr unsafe.Pointer, sz uintptr) { throw("msan") }
+func msanfree(addr unsafe.Pointer, sz uintptr)   { throw("msan") }
diff --git a/libgo/go/runtime/mstkbar.go b/libgo/go/runtime/mstkbar.go
new file mode 100644 (file)
index 0000000..016625a
--- /dev/null
@@ -0,0 +1,365 @@
+// Copyright 2015 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.
+
+// Garbage collector: stack barriers
+//
+// Stack barriers enable the garbage collector to determine how much
+// of a gorountine stack has changed between when a stack is scanned
+// during the concurrent scan phase and when it is re-scanned during
+// the stop-the-world mark termination phase. Mark termination only
+// needs to re-scan the changed part, so for deep stacks this can
+// significantly reduce GC pause time compared to the alternative of
+// re-scanning whole stacks. The deeper the stacks, the more stack
+// barriers help.
+//
+// When stacks are scanned during the concurrent scan phase, the stack
+// scan installs stack barriers by selecting stack frames and
+// overwriting the saved return PCs (or link registers) of these
+// frames with the PC of a "stack barrier trampoline". Later, when a
+// selected frame returns, it "returns" to this trampoline instead of
+// returning to its actual caller. The trampoline records that the
+// stack has unwound past this frame and jumps to the original return
+// PC recorded when the stack barrier was installed. Mark termination
+// re-scans only as far as the first frame that hasn't hit a stack
+// barrier and then removes and un-hit stack barriers.
+//
+// This scheme is very lightweight. No special code is required in the
+// mutator to record stack unwinding and the trampoline is only a few
+// assembly instructions.
+//
+// Book-keeping
+// ------------
+//
+// The primary cost of stack barriers is book-keeping: the runtime has
+// to record the locations of all stack barriers and the original
+// return PCs in order to return to the correct caller when a stack
+// barrier is hit and so it can remove un-hit stack barriers. In order
+// to minimize this cost, the Go runtime places stack barriers in
+// exponentially-spaced frames, starting 1K past the current frame.
+// The book-keeping structure hence grows logarithmically with the
+// size of the stack and mark termination re-scans at most twice as
+// much stack as necessary.
+//
+// The runtime reserves space for this book-keeping structure at the
+// top of the stack allocation itself (just above the outermost
+// frame). This is necessary because the regular memory allocator can
+// itself grow the stack, and hence can't be used when allocating
+// stack-related structures.
+//
+// For debugging, the runtime also supports installing stack barriers
+// at every frame. However, this requires significantly more
+// book-keeping space.
+//
+// Correctness
+// -----------
+//
+// The runtime and the compiler cooperate to ensure that all objects
+// reachable from the stack as of mark termination are marked.
+// Anything unchanged since the concurrent scan phase will be marked
+// because it is marked by the concurrent scan. After the concurrent
+// scan, there are three possible classes of stack modifications that
+// must be tracked:
+//
+// 1) Mutator writes below the lowest un-hit stack barrier. This
+// includes all writes performed by an executing function to its own
+// stack frame. This part of the stack will be re-scanned by mark
+// termination, which will mark any objects made reachable from
+// modifications to this part of the stack.
+//
+// 2) Mutator writes above the lowest un-hit stack barrier. It's
+// possible for a mutator to modify the stack above the lowest un-hit
+// stack barrier if a higher frame has passed down a pointer to a
+// stack variable in its frame. This is called an "up-pointer". The
+// compiler ensures that writes through up-pointers have an
+// accompanying write barrier (it simply doesn't distinguish between
+// writes through up-pointers and writes through heap pointers). This
+// write barrier marks any object made reachable from modifications to
+// this part of the stack.
+//
+// 3) Runtime writes to the stack. Various runtime operations such as
+// sends to unbuffered channels can write to arbitrary parts of the
+// stack, including above the lowest un-hit stack barrier. We solve
+// this in two ways. In many cases, the runtime can perform an
+// explicit write barrier operation like in case 2. However, in the
+// case of bulk memory move (typedmemmove), the runtime doesn't
+// necessary have ready access to a pointer bitmap for the memory
+// being copied, so it simply unwinds any stack barriers below the
+// destination.
+//
+// Gotchas
+// -------
+//
+// Anything that inspects or manipulates the stack potentially needs
+// to understand stack barriers. The most obvious case is that
+// gentraceback needs to use the original return PC when it encounters
+// the stack barrier trampoline. Anything that unwinds the stack such
+// as panic/recover must unwind stack barriers in tandem with
+// unwinding the stack.
+//
+// Stack barriers require that any goroutine whose stack has been
+// scanned must execute write barriers. Go solves this by simply
+// enabling write barriers globally during the concurrent scan phase.
+// However, traditionally, write barriers are not enabled during this
+// phase.
+//
+// Synchronization
+// ---------------
+//
+// For the most part, accessing and modifying stack barriers is
+// synchronized around GC safe points. Installing stack barriers
+// forces the G to a safe point, while all other operations that
+// modify stack barriers run on the G and prevent it from reaching a
+// safe point.
+//
+// Subtlety arises when a G may be tracebacked when *not* at a safe
+// point. This happens during sigprof. For this, each G has a "stack
+// barrier lock" (see gcLockStackBarriers, gcUnlockStackBarriers).
+// Operations that manipulate stack barriers acquire this lock, while
+// sigprof tries to acquire it and simply skips the traceback if it
+// can't acquire it. There is one exception for performance and
+// complexity reasons: hitting a stack barrier manipulates the stack
+// barrier list without acquiring the stack barrier lock. For this,
+// gentraceback performs a special fix up if the traceback starts in
+// the stack barrier function.
+
+package runtime
+
+import (
+       "runtime/internal/atomic"
+       "runtime/internal/sys"
+       "unsafe"
+)
+
+const debugStackBarrier = false
+
+// firstStackBarrierOffset is the approximate byte offset at
+// which to place the first stack barrier from the current SP.
+// This is a lower bound on how much stack will have to be
+// re-scanned during mark termination. Subsequent barriers are
+// placed at firstStackBarrierOffset * 2^n offsets.
+//
+// For debugging, this can be set to 0, which will install a
+// stack barrier at every frame. If you do this, you may also
+// have to raise _StackMin, since the stack barrier
+// bookkeeping will use a large amount of each stack.
+var firstStackBarrierOffset = 1024
+
+// gcMaxStackBarriers returns the maximum number of stack barriers
+// that can be installed in a stack of stackSize bytes.
+func gcMaxStackBarriers(stackSize int) (n int) {
+       if firstStackBarrierOffset == 0 {
+               // Special debugging case for inserting stack barriers
+               // at every frame. Steal half of the stack for the
+               // []stkbar. Technically, if the stack were to consist
+               // solely of return PCs we would need two thirds of
+               // the stack, but stealing that much breaks things and
+               // this doesn't happen in practice.
+               return stackSize / 2 / int(unsafe.Sizeof(stkbar{}))
+       }
+
+       offset := firstStackBarrierOffset
+       for offset < stackSize {
+               n++
+               offset *= 2
+       }
+       return n + 1
+}
+
+// gcInstallStackBarrier installs a stack barrier over the return PC of frame.
+//go:nowritebarrier
+func gcInstallStackBarrier(gp *g, frame *stkframe) bool {
+       if frame.lr == 0 {
+               if debugStackBarrier {
+                       print("not installing stack barrier with no LR, goid=", gp.goid, "\n")
+               }
+               return false
+       }
+
+       if frame.fn.entry == cgocallback_gofuncPC {
+               // cgocallback_gofunc doesn't return to its LR;
+               // instead, its return path puts LR in g.sched.pc and
+               // switches back to the system stack on which
+               // cgocallback_gofunc was originally called. We can't
+               // have a stack barrier in g.sched.pc, so don't
+               // install one in this frame.
+               if debugStackBarrier {
+                       print("not installing stack barrier over LR of cgocallback_gofunc, goid=", gp.goid, "\n")
+               }
+               return false
+       }
+
+       // Save the return PC and overwrite it with stackBarrier.
+       var lrUintptr uintptr
+       if usesLR {
+               lrUintptr = frame.sp
+       } else {
+               lrUintptr = frame.fp - sys.RegSize
+       }
+       lrPtr := (*sys.Uintreg)(unsafe.Pointer(lrUintptr))
+       if debugStackBarrier {
+               print("install stack barrier at ", hex(lrUintptr), " over ", hex(*lrPtr), ", goid=", gp.goid, "\n")
+               if uintptr(*lrPtr) != frame.lr {
+                       print("frame.lr=", hex(frame.lr))
+                       throw("frame.lr differs from stack LR")
+               }
+       }
+
+       gp.stkbar = gp.stkbar[:len(gp.stkbar)+1]
+       stkbar := &gp.stkbar[len(gp.stkbar)-1]
+       stkbar.savedLRPtr = lrUintptr
+       stkbar.savedLRVal = uintptr(*lrPtr)
+       *lrPtr = sys.Uintreg(stackBarrierPC)
+       return true
+}
+
+// gcRemoveStackBarriers removes all stack barriers installed in gp's stack.
+//go:nowritebarrier
+func gcRemoveStackBarriers(gp *g) {
+       if debugStackBarrier && gp.stkbarPos != 0 {
+               print("hit ", gp.stkbarPos, " stack barriers, goid=", gp.goid, "\n")
+       }
+
+       gcLockStackBarriers(gp)
+
+       // Remove stack barriers that we didn't hit.
+       for _, stkbar := range gp.stkbar[gp.stkbarPos:] {
+               gcRemoveStackBarrier(gp, stkbar)
+       }
+
+       // Clear recorded stack barriers so copystack doesn't try to
+       // adjust them.
+       gp.stkbarPos = 0
+       gp.stkbar = gp.stkbar[:0]
+
+       gcUnlockStackBarriers(gp)
+}
+
+// gcRemoveStackBarrier removes a single stack barrier. It is the
+// inverse operation of gcInstallStackBarrier.
+//
+// This is nosplit to ensure gp's stack does not move.
+//
+//go:nowritebarrier
+//go:nosplit
+func gcRemoveStackBarrier(gp *g, stkbar stkbar) {
+       if debugStackBarrier {
+               print("remove stack barrier at ", hex(stkbar.savedLRPtr), " with ", hex(stkbar.savedLRVal), ", goid=", gp.goid, "\n")
+       }
+       lrPtr := (*sys.Uintreg)(unsafe.Pointer(stkbar.savedLRPtr))
+       if val := *lrPtr; val != sys.Uintreg(stackBarrierPC) {
+               printlock()
+               print("at *", hex(stkbar.savedLRPtr), " expected stack barrier PC ", hex(stackBarrierPC), ", found ", hex(val), ", goid=", gp.goid, "\n")
+               print("gp.stkbar=")
+               gcPrintStkbars(gp, -1)
+               print(", gp.stack=[", hex(gp.stack.lo), ",", hex(gp.stack.hi), ")\n")
+               throw("stack barrier lost")
+       }
+       *lrPtr = sys.Uintreg(stkbar.savedLRVal)
+}
+
+// gcPrintStkbars prints the stack barriers of gp for debugging. It
+// places a "@@@" marker at gp.stkbarPos. If marker >= 0, it will also
+// place a "==>" marker before the marker'th entry.
+func gcPrintStkbars(gp *g, marker int) {
+       print("[")
+       for i, s := range gp.stkbar {
+               if i > 0 {
+                       print(" ")
+               }
+               if i == int(gp.stkbarPos) {
+                       print("@@@ ")
+               }
+               if i == marker {
+                       print("==> ")
+               }
+               print("*", hex(s.savedLRPtr), "=", hex(s.savedLRVal))
+       }
+       if int(gp.stkbarPos) == len(gp.stkbar) {
+               print(" @@@")
+       }
+       if marker == len(gp.stkbar) {
+               print(" ==>")
+       }
+       print("]")
+}
+
+// gcUnwindBarriers marks all stack barriers up the frame containing
+// sp as hit and removes them. This is used during stack unwinding for
+// panic/recover and by heapBitsBulkBarrier to force stack re-scanning
+// when its destination is on the stack.
+//
+// This is nosplit to ensure gp's stack does not move.
+//
+//go:nosplit
+func gcUnwindBarriers(gp *g, sp uintptr) {
+       gcLockStackBarriers(gp)
+       // On LR machines, if there is a stack barrier on the return
+       // from the frame containing sp, this will mark it as hit even
+       // though it isn't, but it's okay to be conservative.
+       before := gp.stkbarPos
+       for int(gp.stkbarPos) < len(gp.stkbar) && gp.stkbar[gp.stkbarPos].savedLRPtr < sp {
+               gcRemoveStackBarrier(gp, gp.stkbar[gp.stkbarPos])
+               gp.stkbarPos++
+       }
+       gcUnlockStackBarriers(gp)
+       if debugStackBarrier && gp.stkbarPos != before {
+               print("skip barriers below ", hex(sp), " in goid=", gp.goid, ": ")
+               // We skipped barriers between the "==>" marker
+               // (before) and the "@@@" marker (gp.stkbarPos).
+               gcPrintStkbars(gp, int(before))
+               print("\n")
+       }
+}
+
+// nextBarrierPC returns the original return PC of the next stack barrier.
+// Used by getcallerpc, so it must be nosplit.
+//go:nosplit
+func nextBarrierPC() uintptr {
+       gp := getg()
+       return gp.stkbar[gp.stkbarPos].savedLRVal
+}
+
+// setNextBarrierPC sets the return PC of the next stack barrier.
+// Used by setcallerpc, so it must be nosplit.
+//go:nosplit
+func setNextBarrierPC(pc uintptr) {
+       gp := getg()
+       gcLockStackBarriers(gp)
+       gp.stkbar[gp.stkbarPos].savedLRVal = pc
+       gcUnlockStackBarriers(gp)
+}
+
+// gcLockStackBarriers synchronizes with tracebacks of gp's stack
+// during sigprof for installation or removal of stack barriers. It
+// blocks until any current sigprof is done tracebacking gp's stack
+// and then disallows profiling tracebacks of gp's stack.
+//
+// This is necessary because a sigprof during barrier installation or
+// removal could observe inconsistencies between the stkbar array and
+// the stack itself and crash.
+//
+//go:nosplit
+func gcLockStackBarriers(gp *g) {
+       // Disable preemption so scanstack cannot run while the caller
+       // is manipulating the stack barriers.
+       acquirem()
+       for !atomic.Cas(&gp.stackLock, 0, 1) {
+               osyield()
+       }
+}
+
+//go:nosplit
+func gcTryLockStackBarriers(gp *g) bool {
+       mp := acquirem()
+       result := atomic.Cas(&gp.stackLock, 0, 1)
+       if !result {
+               releasem(mp)
+       }
+       return result
+}
+
+func gcUnlockStackBarriers(gp *g) {
+       atomic.Store(&gp.stackLock, 0)
+       releasem(getg().m)
+}
diff --git a/libgo/go/runtime/os1_linux_generic.go b/libgo/go/runtime/os1_linux_generic.go
new file mode 100644 (file)
index 0000000..2c8b743
--- /dev/null
@@ -0,0 +1,27 @@
+// 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 !mips64
+// +build !mips64le
+// +build linux
+
+package runtime
+
+var sigset_all = sigset{^uint32(0), ^uint32(0)}
+
+func sigaddset(mask *sigset, i int) {
+       (*mask)[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
+}
+
+func sigdelset(mask *sigset, i int) {
+       (*mask)[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
+}
+
+func sigfillset(mask *uint64) {
+       *mask = ^uint64(0)
+}
+
+func sigcopyset(mask *sigset, m sigmask) {
+       copy((*mask)[:], m[:])
+}
diff --git a/libgo/go/runtime/os1_linux_mips64x.go b/libgo/go/runtime/os1_linux_mips64x.go
new file mode 100644 (file)
index 0000000..701e979
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2015 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 mips64 mips64le
+// +build linux
+
+package runtime
+
+var sigset_all = sigset{^uint64(0), ^uint64(0)}
+
+func sigaddset(mask *sigset, i int) {
+       (*mask)[(i-1)/64] |= 1 << ((uint32(i) - 1) & 63)
+}
+
+func sigdelset(mask *sigset, i int) {
+       (*mask)[(i-1)/64] &^= 1 << ((uint32(i) - 1) & 63)
+}
+
+func sigfillset(mask *[2]uint64) {
+       (*mask)[0], (*mask)[1] = ^uint64(0), ^uint64(0)
+}
+
+func sigcopyset(mask *sigset, m sigmask) {
+       (*mask)[0] = uint64(m[0]) | uint64(m[1])<<32
+}
diff --git a/libgo/go/runtime/os2_linux_generic.go b/libgo/go/runtime/os2_linux_generic.go
new file mode 100644 (file)
index 0000000..01e6c8a
--- /dev/null
@@ -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.
+
+// +build !mips64
+// +build !mips64le
+// +build linux
+
+package runtime
+
+const (
+       _SS_DISABLE  = 2
+       _NSIG        = 65
+       _SI_USER     = 0
+       _SIG_BLOCK   = 0
+       _SIG_UNBLOCK = 1
+       _SIG_SETMASK = 2
+       _RLIMIT_AS   = 9
+)
+
+// It's hard to tease out exactly how big a Sigset is, but
+// rt_sigprocmask crashes if we get it wrong, so if binaries
+// are running, this is right.
+type sigset [2]uint32
+
+type rlimit struct {
+       rlim_cur uintptr
+       rlim_max uintptr
+}
diff --git a/libgo/go/runtime/os2_linux_mips64x.go b/libgo/go/runtime/os2_linux_mips64x.go
new file mode 100644 (file)
index 0000000..9a6a92a
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2015 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
+// +build mips64 mips64le
+
+package runtime
+
+const (
+       _SS_DISABLE  = 2
+       _NSIG        = 65
+       _SI_USER     = 0
+       _SIG_BLOCK   = 1
+       _SIG_UNBLOCK = 2
+       _SIG_SETMASK = 3
+       _RLIMIT_AS   = 6
+)
+
+type sigset [2]uint64
+
+type rlimit struct {
+       rlim_cur uintptr
+       rlim_max uintptr
+}
diff --git a/libgo/go/runtime/os_android.go b/libgo/go/runtime/os_android.go
new file mode 100644 (file)
index 0000000..52c8c86
--- /dev/null
@@ -0,0 +1,15 @@
+// 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 runtime
+
+import _ "unsafe" // for go:cgo_export_static and go:cgo_export_dynamic
+
+// Export the main function.
+//
+// Used by the app package to start all-Go Android apps that are
+// loaded via JNI. See golang.org/x/mobile/app.
+
+//go:cgo_export_static main.main
+//go:cgo_export_dynamic main.main
diff --git a/libgo/go/runtime/os_linux_mips64x.go b/libgo/go/runtime/os_linux_mips64x.go
new file mode 100644 (file)
index 0000000..4d2e9e8
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2015 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 mips64 mips64le
+// +build linux
+
+package runtime
+
+var randomNumber uint32
+
+//go:nosplit
+func cputicks() int64 {
+       // Currently cputicks() is used in blocking profiler and to seed fastrand1().
+       // nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
+       // randomNumber provides better seeding of fastrand1.
+       return nanotime() + int64(randomNumber)
+}
index 44a385088262c37df1c912bf9cf23b779428be4c..bfa7b3b47471eee3646aaa29b5d962ec24c9eeca 100644 (file)
@@ -22,11 +22,8 @@ func allocateTransient1M() {
        }
 }
 
+//go:noinline
 func allocateTransient2M() {
-       // prevent inlining
-       if memSink == nil {
-               panic("bad")
-       }
        memSink = make([]byte, 2<<20)
 }
 
@@ -75,21 +72,22 @@ func TestMemoryProfiler(t *testing.T) {
        memoryProfilerRun++
 
        tests := []string{
+
                fmt.Sprintf(`%v: %v \[%v: %v\] @ 0x[0-9,a-f x]+
-#      0x[0-9,a-f]+    pprof_test\.allocatePersistent1K\+0x[0-9,a-f]+  .*/mprof_test\.go:43
-#      0x[0-9,a-f]+    runtime_pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+    .*/mprof_test\.go:66
+#      0x[0-9,a-f]+    pprof_test\.allocatePersistent1K\+0x[0-9,a-f]+  .*/mprof_test\.go:40
+#      0x[0-9,a-f]+    runtime_pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+    .*/mprof_test\.go:63
 `, 32*memoryProfilerRun, 1024*memoryProfilerRun, 32*memoryProfilerRun, 1024*memoryProfilerRun),
 
                fmt.Sprintf(`0: 0 \[%v: %v\] @ 0x[0-9,a-f x]+
 #      0x[0-9,a-f]+    pprof_test\.allocateTransient1M\+0x[0-9,a-f]+   .*/mprof_test.go:21
-#      0x[0-9,a-f]+    runtime_pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+    .*/mprof_test.go:64
+#      0x[0-9,a-f]+    runtime_pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+    .*/mprof_test.go:61
 `, (1<<10)*memoryProfilerRun, (1<<20)*memoryProfilerRun),
 
                // This should start with "0: 0" but gccgo's imprecise
                // GC means that sometimes the value is not collected.
                fmt.Sprintf(`(0|%v): (0|%v) \[%v: %v\] @ 0x[0-9,a-f x]+
-#      0x[0-9,a-f]+    pprof_test\.allocateTransient2M\+0x[0-9,a-f]+   .*/mprof_test.go:30
-#      0x[0-9,a-f]+    runtime_pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+    .*/mprof_test.go:65
+#      0x[0-9,a-f]+    pprof_test\.allocateTransient2M\+0x[0-9,a-f]+   .*/mprof_test.go:27
+#      0x[0-9,a-f]+    runtime_pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+    .*/mprof_test.go:62
 `, memoryProfilerRun, (2<<20)*memoryProfilerRun, memoryProfilerRun, (2<<20)*memoryProfilerRun),
        }
 
index dcf67cd573f32015df8094c9fafe4cf1d4567221..fa11fda3a08d5711e5460f8590980d38dd7f2193 100644 (file)
@@ -20,8 +20,8 @@ import (
        "text/tabwriter"
 )
 
-// BUG(rsc): Profiles are incomplete and inaccurate on NetBSD and OS X.
-// See https://golang.org/issue/6047 for details.
+// BUG(rsc): Profiles are only as good as the kernel support used to generate them.
+// See https://golang.org/issue/13841 for details about known problems.
 
 // A Profile is a collection of stack traces showing the call sequences
 // that led to instances of a particular event, such as allocation.
@@ -579,6 +579,14 @@ var cpu struct {
 // StartCPUProfile enables CPU profiling for the current process.
 // While profiling, the profile will be buffered and written to w.
 // StartCPUProfile returns an error if profiling is already enabled.
+//
+// On Unix-like systems, StartCPUProfile does not work by default for
+// Go code built with -buildmode=c-archive or -buildmode=c-shared.
+// StartCPUProfile relies on the SIGPROF signal, but that signal will
+// be delivered to the main program's SIGPROF signal handler (if any)
+// not to the one used by Go.  To make it work, call os/signal.Notify
+// for syscall.SIGPROF, but note that doing so may break any profiling
+// being done by the main program.
 func StartCPUProfile(w io.Writer) error {
        // The runtime routines allow a variable profiling rate,
        // but in practice operating systems cannot trigger signals
index c32b84758a8f91e192db8119eb46ccc8762a8e54..244be05f50ecf3b779127d88a88dd658110bc8d8 100644 (file)
@@ -23,14 +23,14 @@ import (
        "unsafe"
 )
 
-func cpuHogger(f func()) {
+func cpuHogger(f func(), dur time.Duration) {
        // We only need to get one 100 Hz clock tick, so we've got
-       // a 25x safety buffer.
+       // a large safety buffer.
        // But do at least 500 iterations (which should take about 100ms),
        // otherwise TestCPUProfileMultithreaded can fail if only one
-       // thread is scheduled during the 250ms period.
+       // thread is scheduled during the testing period.
        t0 := time.Now()
-       for i := 0; i < 500 || time.Since(t0) < 250*time.Millisecond; i++ {
+       for i := 0; i < 500 || time.Since(t0) < dur; i++ {
                f()
        }
 }
@@ -68,20 +68,20 @@ func cpuHog2() {
 }
 
 func TestCPUProfile(t *testing.T) {
-       testCPUProfile(t, []string{"pprof_test.cpuHog1"}, func() {
-               cpuHogger(cpuHog1)
+       testCPUProfile(t, []string{"pprof_test.cpuHog1"}, func(dur time.Duration) {
+               cpuHogger(cpuHog1, dur)
        })
 }
 
 func TestCPUProfileMultithreaded(t *testing.T) {
        defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
-       testCPUProfile(t, []string{"pprof_test.cpuHog1", "pprof_test.cpuHog2"}, func() {
+       testCPUProfile(t, []string{"pprof_test.cpuHog1", "pprof_test.cpuHog2"}, func(dur time.Duration) {
                c := make(chan int)
                go func() {
-                       cpuHogger(cpuHog1)
+                       cpuHogger(cpuHog1, dur)
                        c <- 1
                }()
-               cpuHogger(cpuHog2)
+               cpuHogger(cpuHog2, dur)
                <-c
        })
 }
@@ -92,8 +92,8 @@ func parseProfile(t *testing.T, bytes []byte, f func(uintptr, []uintptr)) {
        val := *(*[]uintptr)(unsafe.Pointer(&bytes))
        val = val[:l]
 
-       // 5 for the header, 2 for the per-sample header on at least one sample, 3 for the trailer.
-       if l < 5+2+3 {
+       // 5 for the header, 3 for the trailer.
+       if l < 5+3 {
                t.Logf("profile too short: %#x", val)
                if badOS[runtime.GOOS] {
                        t.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime.GOOS)
@@ -120,7 +120,7 @@ func parseProfile(t *testing.T, bytes []byte, f func(uintptr, []uintptr)) {
        }
 }
 
-func testCPUProfile(t *testing.T, need []string, f func()) {
+func testCPUProfile(t *testing.T, need []string, f func(dur time.Duration)) {
        switch runtime.GOOS {
        case "darwin":
                switch runtime.GOARCH {
@@ -138,12 +138,55 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
                t.Skip("skipping on plan9")
        }
 
-       var prof bytes.Buffer
-       if err := StartCPUProfile(&prof); err != nil {
-               t.Fatal(err)
+       const maxDuration = 5 * time.Second
+       // If we're running a long test, start with a long duration
+       // because some of the tests (e.g., TestStackBarrierProfiling)
+       // are trying to make sure something *doesn't* happen.
+       duration := 5 * time.Second
+       if testing.Short() {
+               duration = 200 * time.Millisecond
+       }
+
+       // Profiling tests are inherently flaky, especially on a
+       // loaded system, such as when this test is running with
+       // several others under go test std. If a test fails in a way
+       // that could mean it just didn't run long enough, try with a
+       // longer duration.
+       for duration <= maxDuration {
+               var prof bytes.Buffer
+               if err := StartCPUProfile(&prof); err != nil {
+                       t.Fatal(err)
+               }
+               f(duration)
+               StopCPUProfile()
+
+               if profileOk(t, need, prof, duration) {
+                       return
+               }
+
+               duration *= 2
+               if duration <= maxDuration {
+                       t.Logf("retrying with %s duration", duration)
+               }
+       }
+
+       if badOS[runtime.GOOS] {
+               t.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime.GOOS)
+               return
        }
-       f()
-       StopCPUProfile()
+       // Ignore the failure if the tests are running in a QEMU-based emulator,
+       // QEMU is not perfect at emulating everything.
+       // IN_QEMU environmental variable is set by some of the Go builders.
+       // IN_QEMU=1 indicates that the tests are running in QEMU. See issue 9605.
+       if os.Getenv("IN_QEMU") == "1" {
+               t.Skip("ignore the failure in QEMU; see golang.org/issue/9605")
+               return
+       }
+       t.FailNow()
+}
+
+func profileOk(t *testing.T, need []string, prof bytes.Buffer, duration time.Duration) (ok bool) {
+       ok = true
 
        // Check that profile is well formed and contains need.
        have := make([]uintptr, len(need))
@@ -161,6 +204,10 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
                                        have[i] += count
                                }
                        }
+                       if strings.Contains(f.Name(), "stackBarrier") {
+                               // The runtime should have unwound this.
+                               t.Fatalf("profile includes stackBarrier")
+                       }
                }
        })
        t.Logf("total %d CPU profile samples collected", samples)
@@ -169,11 +216,18 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
                // On some windows machines we end up with
                // not enough samples due to coarse timer
                // resolution. Let it go.
-               t.Skip("too few samples on Windows (golang.org/issue/10842)")
+               t.Log("too few samples on Windows (golang.org/issue/10842)")
+               return false
+       }
+
+       // Check that we got a reasonable number of samples.
+       if ideal := uintptr(duration * 100 / time.Second); samples == 0 || samples < ideal/4 {
+               t.Logf("too few samples; got %d, want at least %d, ideally %d", samples, ideal/4, ideal)
+               ok = false
        }
 
        if len(need) == 0 {
-               return
+               return ok
        }
 
        var total uintptr
@@ -181,9 +235,8 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
                total += have[i]
                t.Logf("%s: %d\n", name, have[i])
        }
-       ok := true
        if total == 0 {
-               t.Logf("no CPU profile samples collected")
+               t.Logf("no samples in expected functions")
                ok = false
        }
        // We'd like to check a reasonable minimum, like
@@ -197,22 +250,7 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
                        ok = false
                }
        }
-
-       if !ok {
-               if badOS[runtime.GOOS] {
-                       t.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime.GOOS)
-                       return
-               }
-               // Ignore the failure if the tests are running in a QEMU-based emulator,
-               // QEMU is not perfect at emulating everything.
-               // IN_QEMU environmental variable is set by some of the Go builders.
-               // IN_QEMU=1 indicates that the tests are running in QEMU. See issue 9605.
-               if os.Getenv("IN_QEMU") == "1" {
-                       t.Skip("ignore the failure in QEMU; see golang.org/issue/9605")
-                       return
-               }
-               t.FailNow()
-       }
+       return ok
 }
 
 // Fork can hang if preempted with signals frequently enough (see issue 5517).
@@ -307,8 +345,8 @@ func TestGoroutineSwitch(t *testing.T) {
 
 // Test that profiling of division operations is okay, especially on ARM. See issue 6681.
 func TestMathBigDivide(t *testing.T) {
-       testCPUProfile(t, nil, func() {
-               t := time.After(5 * time.Second)
+       testCPUProfile(t, nil, func(duration time.Duration) {
+               t := time.After(duration)
                pi := new(big.Int)
                for {
                        for i := 0; i < 100; i++ {
@@ -325,6 +363,64 @@ func TestMathBigDivide(t *testing.T) {
        })
 }
 
+func TestStackBarrierProfiling(t *testing.T) {
+       if (runtime.GOOS == "linux" && runtime.GOARCH == "arm") || runtime.GOOS == "openbsd" || runtime.GOOS == "solaris" || runtime.GOOS == "dragonfly" || runtime.GOOS == "freebsd" {
+               // This test currently triggers a large number of
+               // usleep(100)s. These kernels/arches have poor
+               // resolution timers, so this gives up a whole
+               // scheduling quantum. On Linux and the BSDs (and
+               // probably Solaris), profiling signals are only
+               // generated when a process completes a whole
+               // scheduling quantum, so this test often gets zero
+               // profiling signals and fails.
+               t.Skipf("low resolution timers inhibit profiling signals (golang.org/issue/13405)")
+               return
+       }
+
+       if !strings.Contains(os.Getenv("GODEBUG"), "gcstackbarrierall=1") {
+               // Re-execute this test with constant GC and stack
+               // barriers at every frame.
+               testenv.MustHaveExec(t)
+               if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" {
+                       t.Skip("gcstackbarrierall doesn't work on ppc64")
+               }
+               args := []string{"-test.run=TestStackBarrierProfiling"}
+               if testing.Short() {
+                       args = append(args, "-test.short")
+               }
+               cmd := exec.Command(os.Args[0], args...)
+               cmd.Env = append([]string{"GODEBUG=gcstackbarrierall=1", "GOGC=1"}, os.Environ()...)
+               if out, err := cmd.CombinedOutput(); err != nil {
+                       t.Fatalf("subprocess failed with %v:\n%s", err, out)
+               }
+               return
+       }
+
+       testCPUProfile(t, nil, func(duration time.Duration) {
+               // In long mode, we're likely to get one or two
+               // samples in stackBarrier.
+               t := time.After(duration)
+               for {
+                       deepStack(1000)
+                       select {
+                       case <-t:
+                               return
+                       default:
+                       }
+               }
+       })
+}
+
+var x []byte
+
+func deepStack(depth int) int {
+       if depth == 0 {
+               return 0
+       }
+       x = make([]byte, 1024)
+       return deepStack(depth-1) + 1
+}
+
 // Operating systems that are expected to fail the tests. See issue 6047.
 var badOS = map[string]bool{
        "darwin": true,
diff --git a/libgo/go/runtime/print.go b/libgo/go/runtime/print.go
new file mode 100644 (file)
index 0000000..f789f89
--- /dev/null
@@ -0,0 +1,221 @@
+// 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 runtime
+
+import "unsafe"
+
+// The compiler knows that a print of a value of this type
+// should use printhex instead of printuint (decimal).
+type hex uint64
+
+func bytes(s string) (ret []byte) {
+       rp := (*slice)(unsafe.Pointer(&ret))
+       sp := stringStructOf(&s)
+       rp.array = sp.str
+       rp.len = sp.len
+       rp.cap = sp.len
+       return
+}
+
+var debuglock mutex
+
+// The compiler emits calls to printlock and printunlock around
+// the multiple calls that implement a single Go print or println
+// statement. Some of the print helpers (printsp, for example)
+// call print recursively. There is also the problem of a crash
+// happening during the print routines and needing to acquire
+// the print lock to print information about the crash.
+// For both these reasons, let a thread acquire the printlock 'recursively'.
+
+func printlock() {
+       mp := getg().m
+       mp.locks++ // do not reschedule between printlock++ and lock(&debuglock).
+       mp.printlock++
+       if mp.printlock == 1 {
+               lock(&debuglock)
+       }
+       mp.locks-- // now we know debuglock is held and holding up mp.locks for us.
+}
+
+func printunlock() {
+       mp := getg().m
+       mp.printlock--
+       if mp.printlock == 0 {
+               unlock(&debuglock)
+       }
+}
+
+// write to goroutine-local buffer if diverting output,
+// or else standard error.
+func gwrite(b []byte) {
+       if len(b) == 0 {
+               return
+       }
+       gp := getg()
+       if gp == nil || gp.writebuf == nil {
+               writeErr(b)
+               return
+       }
+
+       n := copy(gp.writebuf[len(gp.writebuf):cap(gp.writebuf)], b)
+       gp.writebuf = gp.writebuf[:len(gp.writebuf)+n]
+}
+
+func printsp() {
+       print(" ")
+}
+
+func printnl() {
+       print("\n")
+}
+
+func printbool(v bool) {
+       if v {
+               print("true")
+       } else {
+               print("false")
+       }
+}
+
+func printfloat(v float64) {
+       switch {
+       case v != v:
+               print("NaN")
+               return
+       case v+v == v && v > 0:
+               print("+Inf")
+               return
+       case v+v == v && v < 0:
+               print("-Inf")
+               return
+       }
+
+       const n = 7 // digits printed
+       var buf [n + 7]byte
+       buf[0] = '+'
+       e := 0 // exp
+       if v == 0 {
+               if 1/v < 0 {
+                       buf[0] = '-'
+               }
+       } else {
+               if v < 0 {
+                       v = -v
+                       buf[0] = '-'
+               }
+
+               // normalize
+               for v >= 10 {
+                       e++
+                       v /= 10
+               }
+               for v < 1 {
+                       e--
+                       v *= 10
+               }
+
+               // round
+               h := 5.0
+               for i := 0; i < n; i++ {
+                       h /= 10
+               }
+               v += h
+               if v >= 10 {
+                       e++
+                       v /= 10
+               }
+       }
+
+       // format +d.dddd+edd
+       for i := 0; i < n; i++ {
+               s := int(v)
+               buf[i+2] = byte(s + '0')
+               v -= float64(s)
+               v *= 10
+       }
+       buf[1] = buf[2]
+       buf[2] = '.'
+
+       buf[n+2] = 'e'
+       buf[n+3] = '+'
+       if e < 0 {
+               e = -e
+               buf[n+3] = '-'
+       }
+
+       buf[n+4] = byte(e/100) + '0'
+       buf[n+5] = byte(e/10)%10 + '0'
+       buf[n+6] = byte(e%10) + '0'
+       gwrite(buf[:])
+}
+
+func printcomplex(c complex128) {
+       print("(", real(c), imag(c), "i)")
+}
+
+func printuint(v uint64) {
+       var buf [100]byte
+       i := len(buf)
+       for i--; i > 0; i-- {
+               buf[i] = byte(v%10 + '0')
+               if v < 10 {
+                       break
+               }
+               v /= 10
+       }
+       gwrite(buf[i:])
+}
+
+func printint(v int64) {
+       if v < 0 {
+               print("-")
+               v = -v
+       }
+       printuint(uint64(v))
+}
+
+func printhex(v uint64) {
+       const dig = "0123456789abcdef"
+       var buf [100]byte
+       i := len(buf)
+       for i--; i > 0; i-- {
+               buf[i] = dig[v%16]
+               if v < 16 {
+                       break
+               }
+               v /= 16
+       }
+       i--
+       buf[i] = 'x'
+       i--
+       buf[i] = '0'
+       gwrite(buf[i:])
+}
+
+func printpointer(p unsafe.Pointer) {
+       printhex(uint64(uintptr(p)))
+}
+
+func printstring(s string) {
+       if uintptr(len(s)) > maxstring {
+               gwrite(bytes("[string too long]"))
+               return
+       }
+       gwrite(bytes(s))
+}
+
+func printslice(s []byte) {
+       sp := (*slice)(unsafe.Pointer(&s))
+       print("[", len(s), "/", cap(s), "]")
+       printpointer(unsafe.Pointer(sp.array))
+}
+
+func printeface(e eface) {
+       print("(", e._type, ",", e.data, ")")
+}
+
+func printiface(i iface) {
+       print("(", i.tab, ",", i.data, ")")
+}
index 4350e8f89d22d74d4bed58cc61884fb502a3a606..37adad570b7dafe7933c34d351650ace5f3c4cb5 100644 (file)
@@ -6,8 +6,10 @@ package runtime_test
 
 import (
        "math"
+       "net"
        "runtime"
        "runtime/debug"
+       "strings"
        "sync"
        "sync/atomic"
        "syscall"
@@ -132,6 +134,79 @@ func TestGoroutineParallelism(t *testing.T) {
        }
 }
 
+// Test that all runnable goroutines are scheduled at the same time.
+func TestGoroutineParallelism2(t *testing.T) {
+       //testGoroutineParallelism2(t, false, false)
+       testGoroutineParallelism2(t, true, false)
+       testGoroutineParallelism2(t, false, true)
+       testGoroutineParallelism2(t, true, true)
+}
+
+func testGoroutineParallelism2(t *testing.T, load, netpoll bool) {
+       if runtime.NumCPU() == 1 {
+               // Takes too long, too easy to deadlock, etc.
+               t.Skip("skipping on uniprocessor")
+       }
+       P := 4
+       N := 10
+       if testing.Short() {
+               N = 3
+       }
+       defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
+       // If runtime triggers a forced GC during this test then it will deadlock,
+       // since the goroutines can't be stopped/preempted.
+       // Disable GC for this test (see issue #10958).
+       defer debug.SetGCPercent(debug.SetGCPercent(-1))
+       for try := 0; try < N; try++ {
+               if load {
+                       // Create P goroutines and wait until they all run.
+                       // When we run the actual test below, worker threads
+                       // running the goroutines will start parking.
+                       done := make(chan bool)
+                       x := uint32(0)
+                       for p := 0; p < P; p++ {
+                               go func() {
+                                       if atomic.AddUint32(&x, 1) == uint32(P) {
+                                               done <- true
+                                               return
+                                       }
+                                       for atomic.LoadUint32(&x) != uint32(P) {
+                                       }
+                               }()
+                       }
+                       <-done
+               }
+               if netpoll {
+                       // Enable netpoller, affects schedler behavior.
+                       ln, err := net.Listen("tcp", "localhost:0")
+                       if err != nil {
+                               defer ln.Close() // yup, defer in a loop
+                       }
+               }
+               done := make(chan bool)
+               x := uint32(0)
+               // Spawn P goroutines in a nested fashion just to differ from TestGoroutineParallelism.
+               for p := 0; p < P/2; p++ {
+                       go func(p int) {
+                               for p2 := 0; p2 < 2; p2++ {
+                                       go func(p2 int) {
+                                               for i := 0; i < 3; i++ {
+                                                       expected := uint32(P*i + p*2 + p2)
+                                                       for atomic.LoadUint32(&x) != expected {
+                                                       }
+                                                       atomic.StoreUint32(&x, expected+1)
+                                               }
+                                               done <- true
+                                       }(p2)
+                               }
+                       }(p)
+               }
+               for p := 0; p < P; p++ {
+                       <-done
+               }
+       }
+}
+
 func TestBlockLocked(t *testing.T) {
        const N = 10
        c := make(chan bool)
@@ -257,47 +332,44 @@ func TestPreemptionGC(t *testing.T) {
 }
 
 func TestGCFairness(t *testing.T) {
-       output := executeTest(t, testGCFairnessSource, nil)
+       output := runTestProg(t, "testprog", "GCFairness")
        want := "OK\n"
        if output != want {
                t.Fatalf("want %s, got %s\n", want, output)
        }
 }
 
-const testGCFairnessSource = `
-package main
+func TestNumGoroutine(t *testing.T) {
+       output := runTestProg(t, "testprog", "NumGoroutine")
+       want := "1\n"
+       if output != want {
+               t.Fatalf("want %q, got %q", want, output)
+       }
 
-import (
-       "fmt"
-       "os"
-       "runtime"
-       "time"
-)
+       buf := make([]byte, 1<<20)
 
-func main() {
-       runtime.GOMAXPROCS(1)
-       f, err := os.Open("/dev/null")
-       if os.IsNotExist(err) {
-               // This test tests what it is intended to test only if writes are fast.
-               // If there is no /dev/null, we just don't execute the test.
-               fmt.Println("OK")
-               return
-       }
-       if err != nil {
-               fmt.Println(err)
-               os.Exit(1)
-       }
-       for i := 0; i < 2; i++ {
-               go func() {
-                       for {
-                               f.Write([]byte("."))
-                       }
-               }()
+       // Try up to 10 times for a match before giving up.
+       // This is a fundamentally racy check but it's important
+       // to notice if NumGoroutine and Stack are _always_ out of sync.
+       for i := 0; ; i++ {
+               // Give goroutines about to exit a chance to exit.
+               // The NumGoroutine and Stack below need to see
+               // the same state of the world, so anything we can do
+               // to keep it quiet is good.
+               runtime.Gosched()
+
+               n := runtime.NumGoroutine()
+               buf = buf[:runtime.Stack(buf, true)]
+
+               nstk := strings.Count(string(buf), "goroutine ")
+               if n == nstk {
+                       break
+               }
+               if i >= 10 {
+                       t.Fatalf("NumGoroutine=%d, but found %d goroutines in stack dump: %s", n, nstk, buf)
+               }
        }
-       time.Sleep(10 * time.Millisecond)
-       fmt.Println("OK")
 }
-`
 
 func TestPingPongHog(t *testing.T) {
        if testing.Short() {
diff --git a/libgo/go/runtime/race/testdata/issue12225_test.go b/libgo/go/runtime/race/testdata/issue12225_test.go
new file mode 100644 (file)
index 0000000..0494493
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2015 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 race_test
+
+import "unsafe"
+
+// golang.org/issue/12225
+// The test is that this compiles at all.
+
+//go:noinline
+func convert(s string) []byte {
+       return []byte(s)
+}
+
+func issue12225() {
+       println(*(*int)(unsafe.Pointer(&convert("")[0])))
+       println(*(*int)(unsafe.Pointer(&[]byte("")[0])))
+}
diff --git a/libgo/go/runtime/race/testdata/issue12664_test.go b/libgo/go/runtime/race/testdata/issue12664_test.go
new file mode 100644 (file)
index 0000000..c9f790e
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright 2015 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 race_test
+
+import (
+       "fmt"
+       "testing"
+)
+
+var issue12664 = "hi"
+
+func TestRaceIssue12664(t *testing.T) {
+       c := make(chan struct{})
+       go func() {
+               issue12664 = "bye"
+               close(c)
+       }()
+       fmt.Println(issue12664)
+       <-c
+}
+
+type MyI interface {
+       foo()
+}
+
+type MyT int
+
+func (MyT) foo() {
+}
+
+var issue12664_2 MyT = 0
+
+func TestRaceIssue12664_2(t *testing.T) {
+       c := make(chan struct{})
+       go func() {
+               issue12664_2 = 1
+               close(c)
+       }()
+       func(x MyI) {
+               // Never true, but prevents inlining.
+               if x.(MyT) == -1 {
+                       close(c)
+               }
+       }(issue12664_2)
+       <-c
+}
+
+var issue12664_3 MyT = 0
+
+func TestRaceIssue12664_3(t *testing.T) {
+       c := make(chan struct{})
+       go func() {
+               issue12664_3 = 1
+               close(c)
+       }()
+       var r MyT
+       var i interface{} = r
+       issue12664_3 = i.(MyT)
+       <-c
+}
+
+var issue12664_4 MyT = 0
+
+func TestRaceIssue12664_4(t *testing.T) {
+       c := make(chan struct{})
+       go func() {
+               issue12664_4 = 1
+               close(c)
+       }()
+       var r MyT
+       var i MyI = r
+       issue12664_4 = i.(MyT)
+       <-c
+}
diff --git a/libgo/go/runtime/race/testdata/issue13264_test.go b/libgo/go/runtime/race/testdata/issue13264_test.go
new file mode 100644 (file)
index 0000000..d42290d
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2015 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 race_test
+
+// golang.org/issue/13264
+// The test is that this compiles at all.
+
+func issue13264() {
+       for ; ; []map[int]int{}[0][0] = 0 {
+       }
+}
index bb8ff71831344f2aad7285658bfae45d924d6761..980a9f87d11bc39dc7b5c4228ede813933561a39 100644 (file)
@@ -12,6 +12,13 @@ import (
        "unsafe"
 )
 
+func init() {
+       // We're testing the runtime, so make tracebacks show things
+       // in the runtime. This only raises the level, so it won't
+       // override GOTRACEBACK=crash from the user.
+       SetTracebackEnv("system")
+}
+
 var errf error
 
 func errfn() error {
@@ -303,3 +310,15 @@ func TestAppendSliceGrowth(t *testing.T) {
                }
        }
 }
+
+func TestGoroutineProfileTrivial(t *testing.T) {
+       n1, ok := GoroutineProfile(nil) // should fail, there's at least 1 goroutine
+       if n1 < 1 || ok {
+               t.Fatalf("GoroutineProfile(nil) = %d, %v, want >0, false", n1, ok)
+       }
+
+       n2, ok := GoroutineProfile(make([]StackRecord, n1))
+       if n2 != n1 || !ok {
+               t.Fatalf("GoroutineProfile(%d) = %d, %v, want %d, true", n1, n2, ok, n1)
+       }
+}
diff --git a/libgo/go/runtime/signal2_unix.go b/libgo/go/runtime/signal2_unix.go
new file mode 100644 (file)
index 0000000..3fe625f
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2012 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 runtime
+
+import "unsafe"
+
+//go:noescape
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
+
+// Determines if the signal should be handled by Go and if not, forwards the
+// signal to the handler that was installed before Go's.  Returns whether the
+// signal was forwarded.
+// This is called by the signal handler, and the world may be stopped.
+//go:nosplit
+//go:nowritebarrierrec
+func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
+       if sig >= uint32(len(sigtable)) {
+               return false
+       }
+       fwdFn := fwdSig[sig]
+
+       if !signalsOK {
+               // The only way we can get here is if we are in a
+               // library or archive, we installed a signal handler
+               // at program startup, but the Go runtime has not yet
+               // been initialized.
+               if fwdFn == _SIG_DFL {
+                       dieFromSignal(int32(sig))
+               } else {
+                       sigfwd(fwdFn, sig, info, ctx)
+               }
+               return true
+       }
+
+       flags := sigtable[sig].flags
+
+       // If there is no handler to forward to, no need to forward.
+       if fwdFn == _SIG_DFL {
+               return false
+       }
+
+       // If we aren't handling the signal, forward it.
+       if flags&_SigHandling == 0 {
+               sigfwd(fwdFn, sig, info, ctx)
+               return true
+       }
+
+       // Only forward synchronous signals.
+       c := &sigctxt{info, ctx}
+       if c.sigcode() == _SI_USER || flags&_SigPanic == 0 {
+               return false
+       }
+       // Determine if the signal occurred inside Go code.  We test that:
+       //   (1) we were in a goroutine (i.e., m.curg != nil), and
+       //   (2) we weren't in CGO (i.e., m.curg.syscallsp == 0).
+       g := getg()
+       if g != nil && g.m != nil && g.m.curg != nil && g.m.curg.syscallsp == 0 {
+               return false
+       }
+       // Signal not handled by Go, forward it.
+       if fwdFn != _SIG_IGN {
+               sigfwd(fwdFn, sig, info, ctx)
+       }
+       return true
+}
diff --git a/libgo/go/runtime/signal_linux_mips64x.go b/libgo/go/runtime/signal_linux_mips64x.go
new file mode 100644 (file)
index 0000000..671b916
--- /dev/null
@@ -0,0 +1,70 @@
+// Copyright 2015 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
+// +build mips64 mips64le
+
+package runtime
+
+import (
+       "runtime/internal/sys"
+       "unsafe"
+)
+
+type sigctxt struct {
+       info *siginfo
+       ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *sigcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
+func (c *sigctxt) r0() uint64        { return c.regs().sc_regs[0] }
+func (c *sigctxt) r1() uint64        { return c.regs().sc_regs[1] }
+func (c *sigctxt) r2() uint64        { return c.regs().sc_regs[2] }
+func (c *sigctxt) r3() uint64        { return c.regs().sc_regs[3] }
+func (c *sigctxt) r4() uint64        { return c.regs().sc_regs[4] }
+func (c *sigctxt) r5() uint64        { return c.regs().sc_regs[5] }
+func (c *sigctxt) r6() uint64        { return c.regs().sc_regs[6] }
+func (c *sigctxt) r7() uint64        { return c.regs().sc_regs[7] }
+func (c *sigctxt) r8() uint64        { return c.regs().sc_regs[8] }
+func (c *sigctxt) r9() uint64        { return c.regs().sc_regs[9] }
+func (c *sigctxt) r10() uint64       { return c.regs().sc_regs[10] }
+func (c *sigctxt) r11() uint64       { return c.regs().sc_regs[11] }
+func (c *sigctxt) r12() uint64       { return c.regs().sc_regs[12] }
+func (c *sigctxt) r13() uint64       { return c.regs().sc_regs[13] }
+func (c *sigctxt) r14() uint64       { return c.regs().sc_regs[14] }
+func (c *sigctxt) r15() uint64       { return c.regs().sc_regs[15] }
+func (c *sigctxt) r16() uint64       { return c.regs().sc_regs[16] }
+func (c *sigctxt) r17() uint64       { return c.regs().sc_regs[17] }
+func (c *sigctxt) r18() uint64       { return c.regs().sc_regs[18] }
+func (c *sigctxt) r19() uint64       { return c.regs().sc_regs[19] }
+func (c *sigctxt) r20() uint64       { return c.regs().sc_regs[20] }
+func (c *sigctxt) r21() uint64       { return c.regs().sc_regs[21] }
+func (c *sigctxt) r22() uint64       { return c.regs().sc_regs[22] }
+func (c *sigctxt) r23() uint64       { return c.regs().sc_regs[23] }
+func (c *sigctxt) r24() uint64       { return c.regs().sc_regs[24] }
+func (c *sigctxt) r25() uint64       { return c.regs().sc_regs[25] }
+func (c *sigctxt) r26() uint64       { return c.regs().sc_regs[26] }
+func (c *sigctxt) r27() uint64       { return c.regs().sc_regs[27] }
+func (c *sigctxt) r28() uint64       { return c.regs().sc_regs[28] }
+func (c *sigctxt) r29() uint64       { return c.regs().sc_regs[29] }
+func (c *sigctxt) r30() uint64       { return c.regs().sc_regs[30] }
+func (c *sigctxt) r31() uint64       { return c.regs().sc_regs[31] }
+func (c *sigctxt) sp() uint64        { return c.regs().sc_regs[29] }
+func (c *sigctxt) pc() uint64        { return c.regs().sc_pc }
+func (c *sigctxt) link() uint64      { return c.regs().sc_regs[31] }
+func (c *sigctxt) lo() uint64        { return c.regs().sc_mdlo }
+func (c *sigctxt) hi() uint64        { return c.regs().sc_mdhi }
+
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr }
+
+func (c *sigctxt) set_r30(x uint64)  { c.regs().sc_regs[30] = x }
+func (c *sigctxt) set_pc(x uint64)   { c.regs().sc_pc = x }
+func (c *sigctxt) set_sp(x uint64)   { c.regs().sc_regs[29] = x }
+func (c *sigctxt) set_link(x uint64) { c.regs().sc_regs[31] = x }
+
+func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint64) {
+       *(*uintptr)(add(unsafe.Pointer(c.info), 2*sys.PtrSize)) = uintptr(x)
+}
diff --git a/libgo/go/runtime/signal_mips64x.go b/libgo/go/runtime/signal_mips64x.go
new file mode 100644 (file)
index 0000000..77c2714
--- /dev/null
@@ -0,0 +1,188 @@
+// Copyright 2015 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
+// +build mips64 mips64le
+
+package runtime
+
+import (
+       "runtime/internal/sys"
+       "unsafe"
+)
+
+func dumpregs(c *sigctxt) {
+       print("r0   ", hex(c.r0()), "\t")
+       print("r1   ", hex(c.r1()), "\n")
+       print("r2   ", hex(c.r2()), "\t")
+       print("r3   ", hex(c.r3()), "\n")
+       print("r4   ", hex(c.r4()), "\t")
+       print("r5   ", hex(c.r5()), "\n")
+       print("r6   ", hex(c.r6()), "\t")
+       print("r7   ", hex(c.r7()), "\n")
+       print("r8   ", hex(c.r8()), "\t")
+       print("r9   ", hex(c.r9()), "\n")
+       print("r10  ", hex(c.r10()), "\t")
+       print("r11  ", hex(c.r11()), "\n")
+       print("r12  ", hex(c.r12()), "\t")
+       print("r13  ", hex(c.r13()), "\n")
+       print("r14  ", hex(c.r14()), "\t")
+       print("r15  ", hex(c.r15()), "\n")
+       print("r16  ", hex(c.r16()), "\t")
+       print("r17  ", hex(c.r17()), "\n")
+       print("r18  ", hex(c.r18()), "\t")
+       print("r19  ", hex(c.r19()), "\n")
+       print("r20  ", hex(c.r20()), "\t")
+       print("r21  ", hex(c.r21()), "\n")
+       print("r22  ", hex(c.r22()), "\t")
+       print("r23  ", hex(c.r23()), "\n")
+       print("r24  ", hex(c.r24()), "\t")
+       print("r25  ", hex(c.r25()), "\n")
+       print("r26  ", hex(c.r26()), "\t")
+       print("r27  ", hex(c.r27()), "\n")
+       print("r28  ", hex(c.r28()), "\t")
+       print("r29  ", hex(c.r29()), "\n")
+       print("r30  ", hex(c.r30()), "\t")
+       print("r31  ", hex(c.r31()), "\n")
+       print("pc   ", hex(c.pc()), "\t")
+       print("link ", hex(c.link()), "\n")
+       print("lo   ", hex(c.lo()), "\t")
+       print("hi   ", hex(c.hi()), "\n")
+}
+
+var crashing int32
+
+// May run during STW, so write barriers are not allowed.
+//
+//go:nowritebarrierrec
+func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
+       _g_ := getg()
+       c := &sigctxt{info, ctxt}
+
+       if sig == _SIGPROF {
+               sigprof(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.link()), gp, _g_.m)
+               return
+       }
+       flags := int32(_SigThrow)
+       if sig < uint32(len(sigtable)) {
+               flags = sigtable[sig].flags
+       }
+       if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
+               // Make it look like a call to the signal func.
+               // Have to pass arguments out of band since
+               // augmenting the stack frame would break
+               // the unwinding code.
+               gp.sig = sig
+               gp.sigcode0 = uintptr(c.sigcode())
+               gp.sigcode1 = uintptr(c.sigaddr())
+               gp.sigpc = uintptr(c.pc())
+
+               // We arrange link, and pc to pretend the panicking
+               // function calls sigpanic directly.
+               // Always save LINK to stack so that panics in leaf
+               // functions are correctly handled. This smashes
+               // the stack frame but we're not going back there
+               // anyway.
+               sp := c.sp() - sys.PtrSize
+               c.set_sp(sp)
+               *(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link()
+
+               pc := uintptr(gp.sigpc)
+
+               // If we don't recognize the PC as code
+               // but we do recognize the link register as code,
+               // then assume this was a call to non-code and treat like
+               // pc == 0, to make unwinding show the context.
+               if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
+                       pc = 0
+               }
+
+               // Don't bother saving PC if it's zero, which is
+               // probably a call to a nil func: the old link register
+               // is more useful in the stack trace.
+               if pc != 0 {
+                       c.set_link(uint64(pc))
+               }
+
+               // In case we are panicking from external C code
+               c.set_r30(uint64(uintptr(unsafe.Pointer(gp))))
+               c.set_pc(uint64(funcPC(sigpanic)))
+               return
+       }
+
+       if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
+               if sigsend(sig) {
+                       return
+               }
+       }
+
+       if c.sigcode() == _SI_USER && signal_ignored(sig) {
+               return
+       }
+
+       if flags&_SigKill != 0 {
+               dieFromSignal(int32(sig))
+       }
+
+       if flags&_SigThrow == 0 {
+               return
+       }
+
+       _g_.m.throwing = 1
+       _g_.m.caughtsig.set(gp)
+
+       if crashing == 0 {
+               startpanic()
+       }
+
+       if sig < uint32(len(sigtable)) {
+               print(sigtable[sig].name, "\n")
+       } else {
+               print("Signal ", sig, "\n")
+       }
+
+       print("PC=", hex(c.pc()), " m=", _g_.m.id, "\n")
+       if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
+               print("signal arrived during cgo execution\n")
+               gp = _g_.m.lockedg
+       }
+       print("\n")
+
+       level, _, docrash := gotraceback()
+       if level > 0 {
+               goroutineheader(gp)
+               tracebacktrap(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.link()), gp)
+               if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
+                       // tracebackothers on original m skipped this one; trace it now.
+                       goroutineheader(_g_.m.curg)
+                       traceback(^uintptr(0), ^uintptr(0), 0, gp)
+               } else if crashing == 0 {
+                       tracebackothers(gp)
+                       print("\n")
+               }
+               dumpregs(c)
+       }
+
+       if docrash {
+               crashing++
+               if crashing < sched.mcount {
+                       // There are other m's that need to dump their stacks.
+                       // Relay SIGQUIT to the next m by sending it to the current process.
+                       // All m's that have already received SIGQUIT have signal masks blocking
+                       // receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
+                       // When the last m receives the SIGQUIT, it will fall through to the call to
+                       // crash below. Just in case the relaying gets botched, each m involved in
+                       // the relay sleeps for 5 seconds and then does the crash/exit itself.
+                       // In expected operation, the last m has received the SIGQUIT and run
+                       // crash/exit and the process is gone, all long before any of the
+                       // 5-second sleeps have finished.
+                       print("\n-----\n\n")
+                       raiseproc(_SIGQUIT)
+                       usleep(5 * 1000 * 1000)
+               }
+               crash()
+       }
+
+       exit(2)
+}
diff --git a/libgo/go/runtime/signal_sigtramp.go b/libgo/go/runtime/signal_sigtramp.go
new file mode 100644 (file)
index 0000000..00ab038
--- /dev/null
@@ -0,0 +1,50 @@
+// 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 dragonfly linux netbsd
+
+package runtime
+
+import "unsafe"
+
+// Continuation of the (assembly) sigtramp() logic.
+// This may be called with the world stopped.
+//go:nosplit
+//go:nowritebarrierrec
+func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
+       if sigfwdgo(sig, info, ctx) {
+               return
+       }
+       g := getg()
+       if g == nil {
+               badsignal(uintptr(sig))
+               return
+       }
+
+       // If some non-Go code called sigaltstack, adjust.
+       sp := uintptr(unsafe.Pointer(&sig))
+       if sp < g.m.gsignal.stack.lo || sp >= g.m.gsignal.stack.hi {
+               var st sigaltstackt
+               sigaltstack(nil, &st)
+               if st.ss_flags&_SS_DISABLE != 0 {
+                       setg(nil)
+                       cgocallback(unsafe.Pointer(funcPC(noSignalStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
+               }
+               stsp := uintptr(unsafe.Pointer(st.ss_sp))
+               if sp < stsp || sp >= stsp+st.ss_size {
+                       setg(nil)
+                       cgocallback(unsafe.Pointer(funcPC(sigNotOnStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
+               }
+               g.m.gsignal.stack.lo = stsp
+               g.m.gsignal.stack.hi = stsp + st.ss_size
+               g.m.gsignal.stackguard0 = stsp + _StackGuard
+               g.m.gsignal.stackguard1 = stsp + _StackGuard
+               g.m.gsignal.stackAlloc = st.ss_size
+               g.m.gsignal.stktopsp = getcallersp(unsafe.Pointer(&sig))
+       }
+
+       setg(g.m.gsignal)
+       sighandler(sig, info, ctx, g)
+       setg(g)
+}
diff --git a/libgo/go/runtime/sigtab_linux_generic.go b/libgo/go/runtime/sigtab_linux_generic.go
new file mode 100644 (file)
index 0000000..32c40c4
--- /dev/null
@@ -0,0 +1,82 @@
+// 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 !mips64
+// +build !mips64le
+// +build linux
+
+package runtime
+
+type sigTabT struct {
+       flags int32
+       name  string
+}
+
+var sigtable = [...]sigTabT{
+       /* 0 */ {0, "SIGNONE: no trap"},
+       /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
+       /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
+       /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
+       /* 4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"},
+       /* 5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"},
+       /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
+       /* 7 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
+       /* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},
+       /* 9 */ {0, "SIGKILL: kill"},
+       /* 10 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
+       /* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
+       /* 12 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
+       /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
+       /* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+       /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
+       /* 16 */ {_SigThrow + _SigUnblock, "SIGSTKFLT: stack fault"},
+       /* 17 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"},
+       /* 18 */ {_SigNotify + _SigDefault, "SIGCONT: continue"},
+       /* 19 */ {0, "SIGSTOP: stop, unblockable"},
+       /* 20 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
+       /* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
+       /* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
+       /* 23 */ {_SigNotify, "SIGURG: urgent condition on socket"},
+       /* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
+       /* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
+       /* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
+       /* 27 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"},
+       /* 28 */ {_SigNotify, "SIGWINCH: window size change"},
+       /* 29 */ {_SigNotify, "SIGIO: i/o now possible"},
+       /* 30 */ {_SigNotify, "SIGPWR: power failure restart"},
+       /* 31 */ {_SigNotify, "SIGSYS: bad system call"},
+       /* 32 */ {_SigSetStack + _SigUnblock, "signal 32"}, /* SIGCANCEL; see issue 6997 */
+       /* 33 */ {_SigSetStack + _SigUnblock, "signal 33"}, /* SIGSETXID; see issues 3871, 9400, 12498 */
+       /* 34 */ {_SigNotify, "signal 34"},
+       /* 35 */ {_SigNotify, "signal 35"},
+       /* 36 */ {_SigNotify, "signal 36"},
+       /* 37 */ {_SigNotify, "signal 37"},
+       /* 38 */ {_SigNotify, "signal 38"},
+       /* 39 */ {_SigNotify, "signal 39"},
+       /* 40 */ {_SigNotify, "signal 40"},
+       /* 41 */ {_SigNotify, "signal 41"},
+       /* 42 */ {_SigNotify, "signal 42"},
+       /* 43 */ {_SigNotify, "signal 43"},
+       /* 44 */ {_SigNotify, "signal 44"},
+       /* 45 */ {_SigNotify, "signal 45"},
+       /* 46 */ {_SigNotify, "signal 46"},
+       /* 47 */ {_SigNotify, "signal 47"},
+       /* 48 */ {_SigNotify, "signal 48"},
+       /* 49 */ {_SigNotify, "signal 49"},
+       /* 50 */ {_SigNotify, "signal 50"},
+       /* 51 */ {_SigNotify, "signal 51"},
+       /* 52 */ {_SigNotify, "signal 52"},
+       /* 53 */ {_SigNotify, "signal 53"},
+       /* 54 */ {_SigNotify, "signal 54"},
+       /* 55 */ {_SigNotify, "signal 55"},
+       /* 56 */ {_SigNotify, "signal 56"},
+       /* 57 */ {_SigNotify, "signal 57"},
+       /* 58 */ {_SigNotify, "signal 58"},
+       /* 59 */ {_SigNotify, "signal 59"},
+       /* 60 */ {_SigNotify, "signal 60"},
+       /* 61 */ {_SigNotify, "signal 61"},
+       /* 62 */ {_SigNotify, "signal 62"},
+       /* 63 */ {_SigNotify, "signal 63"},
+       /* 64 */ {_SigNotify, "signal 64"},
+}
diff --git a/libgo/go/runtime/sigtab_linux_mips64x.go b/libgo/go/runtime/sigtab_linux_mips64x.go
new file mode 100644 (file)
index 0000000..dbd50f7
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright 2015 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 mips64 mips64le
+// +build linux
+
+package runtime
+
+type sigTabT struct {
+       flags int32
+       name  string
+}
+
+var sigtable = [...]sigTabT{
+       /* 0 */ {0, "SIGNONE: no trap"},
+       /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
+       /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
+       /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
+       /* 4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"},
+       /* 5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"},
+       /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
+       /* 7 */ {_SigThrow, "SIGEMT"},
+       /* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},
+       /* 9 */ {0, "SIGKILL: kill"},
+       /* 10 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
+       /* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
+       /* 12 */ {_SigNotify, "SIGSYS: bad system call"},
+       /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
+       /* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+       /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
+       /* 16 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
+       /* 17 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
+       /* 18 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"},
+       /* 19 */ {_SigNotify, "SIGPWR: power failure restart"},
+       /* 20 */ {_SigNotify, "SIGWINCH: window size change"},
+       /* 21 */ {_SigNotify, "SIGURG: urgent condition on socket"},
+       /* 22 */ {_SigNotify, "SIGIO: i/o now possible"},
+       /* 23 */ {0, "SIGSTOP: stop, unblockable"},
+       /* 24 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
+       /* 25 */ {_SigNotify + _SigDefault, "SIGCONT: continue"},
+       /* 26 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
+       /* 27 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
+       /* 28 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
+       /* 29 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"},
+       /* 30 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
+       /* 31 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
+       /* 32 */ {_SigSetStack + _SigUnblock, "signal 32"}, /* SIGCANCEL; see issue 6997 */
+       /* 33 */ {_SigSetStack + _SigUnblock, "signal 33"}, /* SIGSETXID; see issues 3871, 9400, 12498 */
+       /* 34 */ {_SigNotify, "signal 34"},
+       /* 35 */ {_SigNotify, "signal 35"},
+       /* 36 */ {_SigNotify, "signal 36"},
+       /* 37 */ {_SigNotify, "signal 37"},
+       /* 38 */ {_SigNotify, "signal 38"},
+       /* 39 */ {_SigNotify, "signal 39"},
+       /* 40 */ {_SigNotify, "signal 40"},
+       /* 41 */ {_SigNotify, "signal 41"},
+       /* 42 */ {_SigNotify, "signal 42"},
+       /* 43 */ {_SigNotify, "signal 43"},
+       /* 44 */ {_SigNotify, "signal 44"},
+       /* 45 */ {_SigNotify, "signal 45"},
+       /* 46 */ {_SigNotify, "signal 46"},
+       /* 47 */ {_SigNotify, "signal 47"},
+       /* 48 */ {_SigNotify, "signal 48"},
+       /* 49 */ {_SigNotify, "signal 49"},
+       /* 50 */ {_SigNotify, "signal 50"},
+       /* 51 */ {_SigNotify, "signal 51"},
+       /* 52 */ {_SigNotify, "signal 52"},
+       /* 53 */ {_SigNotify, "signal 53"},
+       /* 54 */ {_SigNotify, "signal 54"},
+       /* 55 */ {_SigNotify, "signal 55"},
+       /* 56 */ {_SigNotify, "signal 56"},
+       /* 57 */ {_SigNotify, "signal 57"},
+       /* 58 */ {_SigNotify, "signal 58"},
+       /* 59 */ {_SigNotify, "signal 59"},
+       /* 60 */ {_SigNotify, "signal 60"},
+       /* 61 */ {_SigNotify, "signal 61"},
+       /* 62 */ {_SigNotify, "signal 62"},
+       /* 63 */ {_SigNotify, "signal 63"},
+       /* 64 */ {_SigNotify, "signal 64"},
+}
diff --git a/libgo/go/runtime/stack.go b/libgo/go/runtime/stack.go
new file mode 100644 (file)
index 0000000..8105996
--- /dev/null
@@ -0,0 +1,1068 @@
+// 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 runtime
+
+import (
+       "runtime/internal/atomic"
+       "runtime/internal/sys"
+       "unsafe"
+)
+
+/*
+Stack layout parameters.
+Included both by runtime (compiled via 6c) and linkers (compiled via gcc).
+
+The per-goroutine g->stackguard is set to point StackGuard bytes
+above the bottom of the stack.  Each function compares its stack
+pointer against g->stackguard to check for overflow.  To cut one
+instruction from the check sequence for functions with tiny frames,
+the stack is allowed to protrude StackSmall bytes below the stack
+guard.  Functions with large frames don't bother with the check and
+always call morestack.  The sequences are (for amd64, others are
+similar):
+
+       guard = g->stackguard
+       frame = function's stack frame size
+       argsize = size of function arguments (call + return)
+
+       stack frame size <= StackSmall:
+               CMPQ guard, SP
+               JHI 3(PC)
+               MOVQ m->morearg, $(argsize << 32)
+               CALL morestack(SB)
+
+       stack frame size > StackSmall but < StackBig
+               LEAQ (frame-StackSmall)(SP), R0
+               CMPQ guard, R0
+               JHI 3(PC)
+               MOVQ m->morearg, $(argsize << 32)
+               CALL morestack(SB)
+
+       stack frame size >= StackBig:
+               MOVQ m->morearg, $((argsize << 32) | frame)
+               CALL morestack(SB)
+
+The bottom StackGuard - StackSmall bytes are important: there has
+to be enough room to execute functions that refuse to check for
+stack overflow, either because they need to be adjacent to the
+actual caller's frame (deferproc) or because they handle the imminent
+stack overflow (morestack).
+
+For example, deferproc might call malloc, which does one of the
+above checks (without allocating a full frame), which might trigger
+a call to morestack.  This sequence needs to fit in the bottom
+section of the stack.  On amd64, morestack's frame is 40 bytes, and
+deferproc's frame is 56 bytes.  That fits well within the
+StackGuard - StackSmall bytes at the bottom.
+The linkers explore all possible call traces involving non-splitting
+functions to make sure that this limit cannot be violated.
+*/
+
+const (
+       // StackSystem is a number of additional bytes to add
+       // to each stack below the usual guard area for OS-specific
+       // purposes like signal handling. Used on Windows, Plan 9,
+       // and Darwin/ARM because they do not use a separate stack.
+       _StackSystem = sys.GoosWindows*512*sys.PtrSize + sys.GoosPlan9*512 + sys.GoosDarwin*sys.GoarchArm*1024
+
+       // The minimum size of stack used by Go code
+       _StackMin = 2048
+
+       // The minimum stack size to allocate.
+       // The hackery here rounds FixedStack0 up to a power of 2.
+       _FixedStack0 = _StackMin + _StackSystem
+       _FixedStack1 = _FixedStack0 - 1
+       _FixedStack2 = _FixedStack1 | (_FixedStack1 >> 1)
+       _FixedStack3 = _FixedStack2 | (_FixedStack2 >> 2)
+       _FixedStack4 = _FixedStack3 | (_FixedStack3 >> 4)
+       _FixedStack5 = _FixedStack4 | (_FixedStack4 >> 8)
+       _FixedStack6 = _FixedStack5 | (_FixedStack5 >> 16)
+       _FixedStack  = _FixedStack6 + 1
+
+       // Functions that need frames bigger than this use an extra
+       // instruction to do the stack split check, to avoid overflow
+       // in case SP - framesize wraps below zero.
+       // This value can be no bigger than the size of the unmapped
+       // space at zero.
+       _StackBig = 4096
+
+       // The stack guard is a pointer this many bytes above the
+       // bottom of the stack.
+       _StackGuard = 720*sys.StackGuardMultiplier + _StackSystem
+
+       // After a stack split check the SP is allowed to be this
+       // many bytes below the stack guard.  This saves an instruction
+       // in the checking sequence for tiny frames.
+       _StackSmall = 128
+
+       // The maximum number of bytes that a chain of NOSPLIT
+       // functions can use.
+       _StackLimit = _StackGuard - _StackSystem - _StackSmall
+)
+
+// Goroutine preemption request.
+// Stored into g->stackguard0 to cause split stack check failure.
+// Must be greater than any real sp.
+// 0xfffffade in hex.
+const (
+       _StackPreempt = uintptrMask & -1314
+       _StackFork    = uintptrMask & -1234
+)
+
+const (
+       // stackDebug == 0: no logging
+       //            == 1: logging of per-stack operations
+       //            == 2: logging of per-frame operations
+       //            == 3: logging of per-word updates
+       //            == 4: logging of per-word reads
+       stackDebug       = 0
+       stackFromSystem  = 0 // allocate stacks from system memory instead of the heap
+       stackFaultOnFree = 0 // old stacks are mapped noaccess to detect use after free
+       stackPoisonCopy  = 0 // fill stack that should not be accessed with garbage, to detect bad dereferences during copy
+
+       stackCache = 1
+)
+
+const (
+       uintptrMask = 1<<(8*sys.PtrSize) - 1
+       poisonStack = uintptrMask & 0x6868686868686868
+
+       // Goroutine preemption request.
+       // Stored into g->stackguard0 to cause split stack check failure.
+       // Must be greater than any real sp.
+       // 0xfffffade in hex.
+       stackPreempt = uintptrMask & -1314
+
+       // Thread is forking.
+       // Stored into g->stackguard0 to cause split stack check failure.
+       // Must be greater than any real sp.
+       stackFork = uintptrMask & -1234
+)
+
+// Global pool of spans that have free stacks.
+// Stacks are assigned an order according to size.
+//     order = log_2(size/FixedStack)
+// There is a free list for each order.
+// TODO: one lock per order?
+var stackpool [_NumStackOrders]mSpanList
+var stackpoolmu mutex
+
+// Global pool of large stack spans.
+var stackLarge struct {
+       lock mutex
+       free [_MHeapMap_Bits]mSpanList // free lists by log_2(s.npages)
+}
+
+// Cached value of haveexperiment("framepointer")
+var framepointer_enabled bool
+
+func stackinit() {
+       if _StackCacheSize&_PageMask != 0 {
+               throw("cache size must be a multiple of page size")
+       }
+       for i := range stackpool {
+               stackpool[i].init()
+       }
+       for i := range stackLarge.free {
+               stackLarge.free[i].init()
+       }
+}
+
+// stacklog2 returns ⌊log_2(n)⌋.
+func stacklog2(n uintptr) int {
+       log2 := 0
+       for n > 1 {
+               n >>= 1
+               log2++
+       }
+       return log2
+}
+
+// Allocates a stack from the free pool.  Must be called with
+// stackpoolmu held.
+func stackpoolalloc(order uint8) gclinkptr {
+       list := &stackpool[order]
+       s := list.first
+       if s == nil {
+               // no free stacks.  Allocate another span worth.
+               s = mheap_.allocStack(_StackCacheSize >> _PageShift)
+               if s == nil {
+                       throw("out of memory")
+               }
+               if s.ref != 0 {
+                       throw("bad ref")
+               }
+               if s.freelist.ptr() != nil {
+                       throw("bad freelist")
+               }
+               for i := uintptr(0); i < _StackCacheSize; i += _FixedStack << order {
+                       x := gclinkptr(uintptr(s.start)<<_PageShift + i)
+                       x.ptr().next = s.freelist
+                       s.freelist = x
+               }
+               list.insert(s)
+       }
+       x := s.freelist
+       if x.ptr() == nil {
+               throw("span has no free stacks")
+       }
+       s.freelist = x.ptr().next
+       s.ref++
+       if s.freelist.ptr() == nil {
+               // all stacks in s are allocated.
+               list.remove(s)
+       }
+       return x
+}
+
+// Adds stack x to the free pool.  Must be called with stackpoolmu held.
+func stackpoolfree(x gclinkptr, order uint8) {
+       s := mheap_.lookup(unsafe.Pointer(x))
+       if s.state != _MSpanStack {
+               throw("freeing stack not in a stack span")
+       }
+       if s.freelist.ptr() == nil {
+               // s will now have a free stack
+               stackpool[order].insert(s)
+       }
+       x.ptr().next = s.freelist
+       s.freelist = x
+       s.ref--
+       if gcphase == _GCoff && s.ref == 0 {
+               // Span is completely free. Return it to the heap
+               // immediately if we're sweeping.
+               //
+               // If GC is active, we delay the free until the end of
+               // GC to avoid the following type of situation:
+               //
+               // 1) GC starts, scans a SudoG but does not yet mark the SudoG.elem pointer
+               // 2) The stack that pointer points to is copied
+               // 3) The old stack is freed
+               // 4) The containing span is marked free
+               // 5) GC attempts to mark the SudoG.elem pointer. The
+               //    marking fails because the pointer looks like a
+               //    pointer into a free span.
+               //
+               // By not freeing, we prevent step #4 until GC is done.
+               stackpool[order].remove(s)
+               s.freelist = 0
+               mheap_.freeStack(s)
+       }
+}
+
+// stackcacherefill/stackcacherelease implement a global pool of stack segments.
+// The pool is required to prevent unlimited growth of per-thread caches.
+func stackcacherefill(c *mcache, order uint8) {
+       if stackDebug >= 1 {
+               print("stackcacherefill order=", order, "\n")
+       }
+
+       // Grab some stacks from the global cache.
+       // Grab half of the allowed capacity (to prevent thrashing).
+       var list gclinkptr
+       var size uintptr
+       lock(&stackpoolmu)
+       for size < _StackCacheSize/2 {
+               x := stackpoolalloc(order)
+               x.ptr().next = list
+               list = x
+               size += _FixedStack << order
+       }
+       unlock(&stackpoolmu)
+       c.stackcache[order].list = list
+       c.stackcache[order].size = size
+}
+
+func stackcacherelease(c *mcache, order uint8) {
+       if stackDebug >= 1 {
+               print("stackcacherelease order=", order, "\n")
+       }
+       x := c.stackcache[order].list
+       size := c.stackcache[order].size
+       lock(&stackpoolmu)
+       for size > _StackCacheSize/2 {
+               y := x.ptr().next
+               stackpoolfree(x, order)
+               x = y
+               size -= _FixedStack << order
+       }
+       unlock(&stackpoolmu)
+       c.stackcache[order].list = x
+       c.stackcache[order].size = size
+}
+
+func stackcache_clear(c *mcache) {
+       if stackDebug >= 1 {
+               print("stackcache clear\n")
+       }
+       lock(&stackpoolmu)
+       for order := uint8(0); order < _NumStackOrders; order++ {
+               x := c.stackcache[order].list
+               for x.ptr() != nil {
+                       y := x.ptr().next
+                       stackpoolfree(x, order)
+                       x = y
+               }
+               c.stackcache[order].list = 0
+               c.stackcache[order].size = 0
+       }
+       unlock(&stackpoolmu)
+}
+
+func stackalloc(n uint32) (stack, []stkbar) {
+       // Stackalloc must be called on scheduler stack, so that we
+       // never try to grow the stack during the code that stackalloc runs.
+       // Doing so would cause a deadlock (issue 1547).
+       thisg := getg()
+       if thisg != thisg.m.g0 {
+               throw("stackalloc not on scheduler stack")
+       }
+       if n&(n-1) != 0 {
+               throw("stack size not a power of 2")
+       }
+       if stackDebug >= 1 {
+               print("stackalloc ", n, "\n")
+       }
+
+       // Compute the size of stack barrier array.
+       maxstkbar := gcMaxStackBarriers(int(n))
+       nstkbar := unsafe.Sizeof(stkbar{}) * uintptr(maxstkbar)
+
+       if debug.efence != 0 || stackFromSystem != 0 {
+               v := sysAlloc(round(uintptr(n), _PageSize), &memstats.stacks_sys)
+               if v == nil {
+                       throw("out of memory (stackalloc)")
+               }
+               top := uintptr(n) - nstkbar
+               stkbarSlice := slice{add(v, top), 0, maxstkbar}
+               return stack{uintptr(v), uintptr(v) + top}, *(*[]stkbar)(unsafe.Pointer(&stkbarSlice))
+       }
+
+       // Small stacks are allocated with a fixed-size free-list allocator.
+       // If we need a stack of a bigger size, we fall back on allocating
+       // a dedicated span.
+       var v unsafe.Pointer
+       if stackCache != 0 && n < _FixedStack<<_NumStackOrders && n < _StackCacheSize {
+               order := uint8(0)
+               n2 := n
+               for n2 > _FixedStack {
+                       order++
+                       n2 >>= 1
+               }
+               var x gclinkptr
+               c := thisg.m.mcache
+               if c == nil || thisg.m.preemptoff != "" || thisg.m.helpgc != 0 {
+                       // c == nil can happen in the guts of exitsyscall or
+                       // procresize. Just get a stack from the global pool.
+                       // Also don't touch stackcache during gc
+                       // as it's flushed concurrently.
+                       lock(&stackpoolmu)
+                       x = stackpoolalloc(order)
+                       unlock(&stackpoolmu)
+               } else {
+                       x = c.stackcache[order].list
+                       if x.ptr() == nil {
+                               stackcacherefill(c, order)
+                               x = c.stackcache[order].list
+                       }
+                       c.stackcache[order].list = x.ptr().next
+                       c.stackcache[order].size -= uintptr(n)
+               }
+               v = unsafe.Pointer(x)
+       } else {
+               var s *mspan
+               npage := uintptr(n) >> _PageShift
+               log2npage := stacklog2(npage)
+
+               // Try to get a stack from the large stack cache.
+               lock(&stackLarge.lock)
+               if !stackLarge.free[log2npage].isEmpty() {
+                       s = stackLarge.free[log2npage].first
+                       stackLarge.free[log2npage].remove(s)
+               }
+               unlock(&stackLarge.lock)
+
+               if s == nil {
+                       // Allocate a new stack from the heap.
+                       s = mheap_.allocStack(npage)
+                       if s == nil {
+                               throw("out of memory")
+                       }
+               }
+               v = unsafe.Pointer(s.start << _PageShift)
+       }
+
+       if raceenabled {
+               racemalloc(v, uintptr(n))
+       }
+       if msanenabled {
+               msanmalloc(v, uintptr(n))
+       }
+       if stackDebug >= 1 {
+               print("  allocated ", v, "\n")
+       }
+       top := uintptr(n) - nstkbar
+       stkbarSlice := slice{add(v, top), 0, maxstkbar}
+       return stack{uintptr(v), uintptr(v) + top}, *(*[]stkbar)(unsafe.Pointer(&stkbarSlice))
+}
+
+func stackfree(stk stack, n uintptr) {
+       gp := getg()
+       v := unsafe.Pointer(stk.lo)
+       if n&(n-1) != 0 {
+               throw("stack not a power of 2")
+       }
+       if stk.lo+n < stk.hi {
+               throw("bad stack size")
+       }
+       if stackDebug >= 1 {
+               println("stackfree", v, n)
+               memclr(v, n) // for testing, clobber stack data
+       }
+       if debug.efence != 0 || stackFromSystem != 0 {
+               if debug.efence != 0 || stackFaultOnFree != 0 {
+                       sysFault(v, n)
+               } else {
+                       sysFree(v, n, &memstats.stacks_sys)
+               }
+               return
+       }
+       if msanenabled {
+               msanfree(v, n)
+       }
+       if stackCache != 0 && n < _FixedStack<<_NumStackOrders && n < _StackCacheSize {
+               order := uint8(0)
+               n2 := n
+               for n2 > _FixedStack {
+                       order++
+                       n2 >>= 1
+               }
+               x := gclinkptr(v)
+               c := gp.m.mcache
+               if c == nil || gp.m.preemptoff != "" || gp.m.helpgc != 0 {
+                       lock(&stackpoolmu)
+                       stackpoolfree(x, order)
+                       unlock(&stackpoolmu)
+               } else {
+                       if c.stackcache[order].size >= _StackCacheSize {
+                               stackcacherelease(c, order)
+                       }
+                       x.ptr().next = c.stackcache[order].list
+                       c.stackcache[order].list = x
+                       c.stackcache[order].size += n
+               }
+       } else {
+               s := mheap_.lookup(v)
+               if s.state != _MSpanStack {
+                       println(hex(s.start<<_PageShift), v)
+                       throw("bad span state")
+               }
+               if gcphase == _GCoff {
+                       // Free the stack immediately if we're
+                       // sweeping.
+                       mheap_.freeStack(s)
+               } else {
+                       // If the GC is running, we can't return a
+                       // stack span to the heap because it could be
+                       // reused as a heap span, and this state
+                       // change would race with GC. Add it to the
+                       // large stack cache instead.
+                       log2npage := stacklog2(s.npages)
+                       lock(&stackLarge.lock)
+                       stackLarge.free[log2npage].insert(s)
+                       unlock(&stackLarge.lock)
+               }
+       }
+}
+
+var maxstacksize uintptr = 1 << 20 // enough until runtime.main sets it for real
+
+var ptrnames = []string{
+       0: "scalar",
+       1: "ptr",
+}
+
+// Stack frame layout
+//
+// (x86)
+// +------------------+
+// | args from caller |
+// +------------------+ <- frame->argp
+// |  return address  |
+// +------------------+
+// |  caller's BP (*) | (*) if framepointer_enabled && varp < sp
+// +------------------+ <- frame->varp
+// |     locals       |
+// +------------------+
+// |  args to callee  |
+// +------------------+ <- frame->sp
+//
+// (arm)
+// +------------------+
+// | args from caller |
+// +------------------+ <- frame->argp
+// | caller's retaddr |
+// +------------------+ <- frame->varp
+// |     locals       |
+// +------------------+
+// |  args to callee  |
+// +------------------+
+// |  return address  |
+// +------------------+ <- frame->sp
+
+type adjustinfo struct {
+       old   stack
+       delta uintptr // ptr distance from old to new stack (newbase - oldbase)
+       cache pcvalueCache
+}
+
+// Adjustpointer checks whether *vpp is in the old stack described by adjinfo.
+// If so, it rewrites *vpp to point into the new stack.
+func adjustpointer(adjinfo *adjustinfo, vpp unsafe.Pointer) {
+       pp := (*unsafe.Pointer)(vpp)
+       p := *pp
+       if stackDebug >= 4 {
+               print("        ", pp, ":", p, "\n")
+       }
+       if adjinfo.old.lo <= uintptr(p) && uintptr(p) < adjinfo.old.hi {
+               *pp = add(p, adjinfo.delta)
+               if stackDebug >= 3 {
+                       print("        adjust ptr ", pp, ":", p, " -> ", *pp, "\n")
+               }
+       }
+}
+
+// Information from the compiler about the layout of stack frames.
+type bitvector struct {
+       n        int32 // # of bits
+       bytedata *uint8
+}
+
+type gobitvector struct {
+       n        uintptr
+       bytedata []uint8
+}
+
+func gobv(bv bitvector) gobitvector {
+       return gobitvector{
+               uintptr(bv.n),
+               (*[1 << 30]byte)(unsafe.Pointer(bv.bytedata))[:(bv.n+7)/8],
+       }
+}
+
+func ptrbit(bv *gobitvector, i uintptr) uint8 {
+       return (bv.bytedata[i/8] >> (i % 8)) & 1
+}
+
+// bv describes the memory starting at address scanp.
+// Adjust any pointers contained therein.
+func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f *_func) {
+       bv := gobv(*cbv)
+       minp := adjinfo.old.lo
+       maxp := adjinfo.old.hi
+       delta := adjinfo.delta
+       num := uintptr(bv.n)
+       for i := uintptr(0); i < num; i++ {
+               if stackDebug >= 4 {
+                       print("        ", add(scanp, i*sys.PtrSize), ":", ptrnames[ptrbit(&bv, i)], ":", hex(*(*uintptr)(add(scanp, i*sys.PtrSize))), " # ", i, " ", bv.bytedata[i/8], "\n")
+               }
+               if ptrbit(&bv, i) == 1 {
+                       pp := (*uintptr)(add(scanp, i*sys.PtrSize))
+                       p := *pp
+                       if f != nil && 0 < p && p < _PageSize && debug.invalidptr != 0 || p == poisonStack {
+                               // Looks like a junk value in a pointer slot.
+                               // Live analysis wrong?
+                               getg().m.traceback = 2
+                               print("runtime: bad pointer in frame ", funcname(f), " at ", pp, ": ", hex(p), "\n")
+                               throw("invalid stack pointer")
+                       }
+                       if minp <= p && p < maxp {
+                               if stackDebug >= 3 {
+                                       print("adjust ptr ", p, " ", funcname(f), "\n")
+                               }
+                               *pp = p + delta
+                       }
+               }
+       }
+}
+
+// Note: the argument/return area is adjusted by the callee.
+func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
+       adjinfo := (*adjustinfo)(arg)
+       targetpc := frame.continpc
+       if targetpc == 0 {
+               // Frame is dead.
+               return true
+       }
+       f := frame.fn
+       if stackDebug >= 2 {
+               print("    adjusting ", funcname(f), " frame=[", hex(frame.sp), ",", hex(frame.fp), "] pc=", hex(frame.pc), " continpc=", hex(frame.continpc), "\n")
+       }
+       if f.entry == systemstack_switchPC {
+               // A special routine at the bottom of stack of a goroutine that does an systemstack call.
+               // We will allow it to be copied even though we don't
+               // have full GC info for it (because it is written in asm).
+               return true
+       }
+       if targetpc != f.entry {
+               targetpc--
+       }
+       pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, targetpc, &adjinfo.cache)
+       if pcdata == -1 {
+               pcdata = 0 // in prologue
+       }
+
+       // Adjust local variables if stack frame has been allocated.
+       size := frame.varp - frame.sp
+       var minsize uintptr
+       switch sys.TheChar {
+       case '7':
+               minsize = sys.SpAlign
+       default:
+               minsize = sys.MinFrameSize
+       }
+       if size > minsize {
+               var bv bitvector
+               stackmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps))
+               if stackmap == nil || stackmap.n <= 0 {
+                       print("runtime: frame ", funcname(f), " untyped locals ", hex(frame.varp-size), "+", hex(size), "\n")
+                       throw("missing stackmap")
+               }
+               // Locals bitmap information, scan just the pointers in locals.
+               if pcdata < 0 || pcdata >= stackmap.n {
+                       // don't know where we are
+                       print("runtime: pcdata is ", pcdata, " and ", stackmap.n, " locals stack map entries for ", funcname(f), " (targetpc=", targetpc, ")\n")
+                       throw("bad symbol table")
+               }
+               bv = stackmapdata(stackmap, pcdata)
+               size = uintptr(bv.n) * sys.PtrSize
+               if stackDebug >= 3 {
+                       print("      locals ", pcdata, "/", stackmap.n, " ", size/sys.PtrSize, " words ", bv.bytedata, "\n")
+               }
+               adjustpointers(unsafe.Pointer(frame.varp-size), &bv, adjinfo, f)
+       }
+
+       // Adjust saved base pointer if there is one.
+       if sys.TheChar == '6' && frame.argp-frame.varp == 2*sys.RegSize {
+               if !framepointer_enabled {
+                       print("runtime: found space for saved base pointer, but no framepointer experiment\n")
+                       print("argp=", hex(frame.argp), " varp=", hex(frame.varp), "\n")
+                       throw("bad frame layout")
+               }
+               if stackDebug >= 3 {
+                       print("      saved bp\n")
+               }
+               adjustpointer(adjinfo, unsafe.Pointer(frame.varp))
+       }
+
+       // Adjust arguments.
+       if frame.arglen > 0 {
+               var bv bitvector
+               if frame.argmap != nil {
+                       bv = *frame.argmap
+               } else {
+                       stackmap := (*stackmap)(funcdata(f, _FUNCDATA_ArgsPointerMaps))
+                       if stackmap == nil || stackmap.n <= 0 {
+                               print("runtime: frame ", funcname(f), " untyped args ", frame.argp, "+", uintptr(frame.arglen), "\n")
+                               throw("missing stackmap")
+                       }
+                       if pcdata < 0 || pcdata >= stackmap.n {
+                               // don't know where we are
+                               print("runtime: pcdata is ", pcdata, " and ", stackmap.n, " args stack map entries for ", funcname(f), " (targetpc=", targetpc, ")\n")
+                               throw("bad symbol table")
+                       }
+                       bv = stackmapdata(stackmap, pcdata)
+               }
+               if stackDebug >= 3 {
+                       print("      args\n")
+               }
+               adjustpointers(unsafe.Pointer(frame.argp), &bv, adjinfo, nil)
+       }
+       return true
+}
+
+func adjustctxt(gp *g, adjinfo *adjustinfo) {
+       adjustpointer(adjinfo, unsafe.Pointer(&gp.sched.ctxt))
+}
+
+func adjustdefers(gp *g, adjinfo *adjustinfo) {
+       // Adjust defer argument blocks the same way we adjust active stack frames.
+       tracebackdefers(gp, adjustframe, noescape(unsafe.Pointer(adjinfo)))
+
+       // Adjust pointers in the Defer structs.
+       // Defer structs themselves are never on the stack.
+       for d := gp._defer; d != nil; d = d.link {
+               adjustpointer(adjinfo, unsafe.Pointer(&d.fn))
+               adjustpointer(adjinfo, unsafe.Pointer(&d.sp))
+               adjustpointer(adjinfo, unsafe.Pointer(&d._panic))
+       }
+}
+
+func adjustpanics(gp *g, adjinfo *adjustinfo) {
+       // Panics are on stack and already adjusted.
+       // Update pointer to head of list in G.
+       adjustpointer(adjinfo, unsafe.Pointer(&gp._panic))
+}
+
+func adjustsudogs(gp *g, adjinfo *adjustinfo) {
+       // the data elements pointed to by a SudoG structure
+       // might be in the stack.
+       for s := gp.waiting; s != nil; s = s.waitlink {
+               adjustpointer(adjinfo, unsafe.Pointer(&s.elem))
+               adjustpointer(adjinfo, unsafe.Pointer(&s.selectdone))
+       }
+}
+
+func adjuststkbar(gp *g, adjinfo *adjustinfo) {
+       for i := int(gp.stkbarPos); i < len(gp.stkbar); i++ {
+               adjustpointer(adjinfo, unsafe.Pointer(&gp.stkbar[i].savedLRPtr))
+       }
+}
+
+func fillstack(stk stack, b byte) {
+       for p := stk.lo; p < stk.hi; p++ {
+               *(*byte)(unsafe.Pointer(p)) = b
+       }
+}
+
+// Copies gp's stack to a new stack of a different size.
+// Caller must have changed gp status to Gcopystack.
+func copystack(gp *g, newsize uintptr) {
+       if gp.syscallsp != 0 {
+               throw("stack growth not allowed in system call")
+       }
+       old := gp.stack
+       if old.lo == 0 {
+               throw("nil stackbase")
+       }
+       used := old.hi - gp.sched.sp
+
+       // allocate new stack
+       new, newstkbar := stackalloc(uint32(newsize))
+       if stackPoisonCopy != 0 {
+               fillstack(new, 0xfd)
+       }
+       if stackDebug >= 1 {
+               print("copystack gp=", gp, " [", hex(old.lo), " ", hex(old.hi-used), " ", hex(old.hi), "]/", gp.stackAlloc, " -> [", hex(new.lo), " ", hex(new.hi-used), " ", hex(new.hi), "]/", newsize, "\n")
+       }
+
+       // Disallow sigprof scans of this stack and block if there's
+       // one in progress.
+       gcLockStackBarriers(gp)
+
+       // adjust pointers in the to-be-copied frames
+       var adjinfo adjustinfo
+       adjinfo.old = old
+       adjinfo.delta = new.hi - old.hi
+       gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, adjustframe, noescape(unsafe.Pointer(&adjinfo)), 0)
+
+       // adjust other miscellaneous things that have pointers into stacks.
+       adjustctxt(gp, &adjinfo)
+       adjustdefers(gp, &adjinfo)
+       adjustpanics(gp, &adjinfo)
+       adjustsudogs(gp, &adjinfo)
+       adjuststkbar(gp, &adjinfo)
+
+       // copy the stack to the new location
+       if stackPoisonCopy != 0 {
+               fillstack(new, 0xfb)
+       }
+       memmove(unsafe.Pointer(new.hi-used), unsafe.Pointer(old.hi-used), used)
+
+       // copy old stack barriers to new stack barrier array
+       newstkbar = newstkbar[:len(gp.stkbar)]
+       copy(newstkbar, gp.stkbar)
+
+       // Swap out old stack for new one
+       gp.stack = new
+       gp.stackguard0 = new.lo + _StackGuard // NOTE: might clobber a preempt request
+       gp.sched.sp = new.hi - used
+       oldsize := gp.stackAlloc
+       gp.stackAlloc = newsize
+       gp.stkbar = newstkbar
+       gp.stktopsp += adjinfo.delta
+
+       gcUnlockStackBarriers(gp)
+
+       // free old stack
+       if stackPoisonCopy != 0 {
+               fillstack(old, 0xfc)
+       }
+       stackfree(old, oldsize)
+}
+
+// round x up to a power of 2.
+func round2(x int32) int32 {
+       s := uint(0)
+       for 1<<s < x {
+               s++
+       }
+       return 1 << s
+}
+
+// Called from runtime·morestack when more stack is needed.
+// Allocate larger stack and relocate to new stack.
+// Stack growth is multiplicative, for constant amortized cost.
+//
+// g->atomicstatus will be Grunning or Gscanrunning upon entry.
+// If the GC is trying to stop this g then it will set preemptscan to true.
+func newstack() {
+       thisg := getg()
+       // TODO: double check all gp. shouldn't be getg().
+       if thisg.m.morebuf.g.ptr().stackguard0 == stackFork {
+               throw("stack growth after fork")
+       }
+       if thisg.m.morebuf.g.ptr() != thisg.m.curg {
+               print("runtime: newstack called from g=", hex(thisg.m.morebuf.g), "\n"+"\tm=", thisg.m, " m->curg=", thisg.m.curg, " m->g0=", thisg.m.g0, " m->gsignal=", thisg.m.gsignal, "\n")
+               morebuf := thisg.m.morebuf
+               traceback(morebuf.pc, morebuf.sp, morebuf.lr, morebuf.g.ptr())
+               throw("runtime: wrong goroutine in newstack")
+       }
+       if thisg.m.curg.throwsplit {
+               gp := thisg.m.curg
+               // Update syscallsp, syscallpc in case traceback uses them.
+               morebuf := thisg.m.morebuf
+               gp.syscallsp = morebuf.sp
+               gp.syscallpc = morebuf.pc
+               print("runtime: newstack sp=", hex(gp.sched.sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n",
+                       "\tmorebuf={pc:", hex(morebuf.pc), " sp:", hex(morebuf.sp), " lr:", hex(morebuf.lr), "}\n",
+                       "\tsched={pc:", hex(gp.sched.pc), " sp:", hex(gp.sched.sp), " lr:", hex(gp.sched.lr), " ctxt:", gp.sched.ctxt, "}\n")
+
+               traceback(morebuf.pc, morebuf.sp, morebuf.lr, gp)
+               throw("runtime: stack split at bad time")
+       }
+
+       gp := thisg.m.curg
+       morebuf := thisg.m.morebuf
+       thisg.m.morebuf.pc = 0
+       thisg.m.morebuf.lr = 0
+       thisg.m.morebuf.sp = 0
+       thisg.m.morebuf.g = 0
+       rewindmorestack(&gp.sched)
+
+       // NOTE: stackguard0 may change underfoot, if another thread
+       // is about to try to preempt gp. Read it just once and use that same
+       // value now and below.
+       preempt := atomic.Loaduintptr(&gp.stackguard0) == stackPreempt
+
+       // Be conservative about where we preempt.
+       // We are interested in preempting user Go code, not runtime code.
+       // If we're holding locks, mallocing, or preemption is disabled, don't
+       // preempt.
+       // This check is very early in newstack so that even the status change
+       // from Grunning to Gwaiting and back doesn't happen in this case.
+       // That status change by itself can be viewed as a small preemption,
+       // because the GC might change Gwaiting to Gscanwaiting, and then
+       // this goroutine has to wait for the GC to finish before continuing.
+       // If the GC is in some way dependent on this goroutine (for example,
+       // it needs a lock held by the goroutine), that small preemption turns
+       // into a real deadlock.
+       if preempt {
+               if thisg.m.locks != 0 || thisg.m.mallocing != 0 || thisg.m.preemptoff != "" || thisg.m.p.ptr().status != _Prunning {
+                       // Let the goroutine keep running for now.
+                       // gp->preempt is set, so it will be preempted next time.
+                       gp.stackguard0 = gp.stack.lo + _StackGuard
+                       gogo(&gp.sched) // never return
+               }
+       }
+
+       // The goroutine must be executing in order to call newstack,
+       // so it must be Grunning (or Gscanrunning).
+       casgstatus(gp, _Grunning, _Gwaiting)
+       gp.waitreason = "stack growth"
+
+       if gp.stack.lo == 0 {
+               throw("missing stack in newstack")
+       }
+       sp := gp.sched.sp
+       if sys.TheChar == '6' || sys.TheChar == '8' {
+               // The call to morestack cost a word.
+               sp -= sys.PtrSize
+       }
+       if stackDebug >= 1 || sp < gp.stack.lo {
+               print("runtime: newstack sp=", hex(sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n",
+                       "\tmorebuf={pc:", hex(morebuf.pc), " sp:", hex(morebuf.sp), " lr:", hex(morebuf.lr), "}\n",
+                       "\tsched={pc:", hex(gp.sched.pc), " sp:", hex(gp.sched.sp), " lr:", hex(gp.sched.lr), " ctxt:", gp.sched.ctxt, "}\n")
+       }
+       if sp < gp.stack.lo {
+               print("runtime: gp=", gp, ", gp->status=", hex(readgstatus(gp)), "\n ")
+               print("runtime: split stack overflow: ", hex(sp), " < ", hex(gp.stack.lo), "\n")
+               throw("runtime: split stack overflow")
+       }
+
+       if gp.sched.ctxt != nil {
+               // morestack wrote sched.ctxt on its way in here,
+               // without a write barrier. Run the write barrier now.
+               // It is not possible to be preempted between then
+               // and now, so it's okay.
+               writebarrierptr_nostore((*uintptr)(unsafe.Pointer(&gp.sched.ctxt)), uintptr(gp.sched.ctxt))
+       }
+
+       if preempt {
+               if gp == thisg.m.g0 {
+                       throw("runtime: preempt g0")
+               }
+               if thisg.m.p == 0 && thisg.m.locks == 0 {
+                       throw("runtime: g is running but p is not")
+               }
+               if gp.preemptscan {
+                       for !castogscanstatus(gp, _Gwaiting, _Gscanwaiting) {
+                               // Likely to be racing with the GC as
+                               // it sees a _Gwaiting and does the
+                               // stack scan. If so, gcworkdone will
+                               // be set and gcphasework will simply
+                               // return.
+                       }
+                       if !gp.gcscandone {
+                               scanstack(gp)
+                               gp.gcscandone = true
+                       }
+                       gp.preemptscan = false
+                       gp.preempt = false
+                       casfrom_Gscanstatus(gp, _Gscanwaiting, _Gwaiting)
+                       casgstatus(gp, _Gwaiting, _Grunning)
+                       gp.stackguard0 = gp.stack.lo + _StackGuard
+                       gogo(&gp.sched) // never return
+               }
+
+               // Act like goroutine called runtime.Gosched.
+               casgstatus(gp, _Gwaiting, _Grunning)
+               gopreempt_m(gp) // never return
+       }
+
+       // Allocate a bigger segment and move the stack.
+       oldsize := int(gp.stackAlloc)
+       newsize := oldsize * 2
+       if uintptr(newsize) > maxstacksize {
+               print("runtime: goroutine stack exceeds ", maxstacksize, "-byte limit\n")
+               throw("stack overflow")
+       }
+
+       casgstatus(gp, _Gwaiting, _Gcopystack)
+
+       // The concurrent GC will not scan the stack while we are doing the copy since
+       // the gp is in a Gcopystack status.
+       copystack(gp, uintptr(newsize))
+       if stackDebug >= 1 {
+               print("stack grow done\n")
+       }
+       casgstatus(gp, _Gcopystack, _Grunning)
+       gogo(&gp.sched)
+}
+
+//go:nosplit
+func nilfunc() {
+       *(*uint8)(nil) = 0
+}
+
+// adjust Gobuf as if it executed a call to fn
+// and then did an immediate gosave.
+func gostartcallfn(gobuf *gobuf, fv *funcval) {
+       var fn unsafe.Pointer
+       if fv != nil {
+               fn = unsafe.Pointer(fv.fn)
+       } else {
+               fn = unsafe.Pointer(funcPC(nilfunc))
+       }
+       gostartcall(gobuf, fn, unsafe.Pointer(fv))
+}
+
+// Maybe shrink the stack being used by gp.
+// Called at garbage collection time.
+func shrinkstack(gp *g) {
+       if readgstatus(gp) == _Gdead {
+               if gp.stack.lo != 0 {
+                       // Free whole stack - it will get reallocated
+                       // if G is used again.
+                       stackfree(gp.stack, gp.stackAlloc)
+                       gp.stack.lo = 0
+                       gp.stack.hi = 0
+                       gp.stkbar = nil
+                       gp.stkbarPos = 0
+               }
+               return
+       }
+       if gp.stack.lo == 0 {
+               throw("missing stack in shrinkstack")
+       }
+
+       if debug.gcshrinkstackoff > 0 {
+               return
+       }
+
+       oldsize := gp.stackAlloc
+       newsize := oldsize / 2
+       // Don't shrink the allocation below the minimum-sized stack
+       // allocation.
+       if newsize < _FixedStack {
+               return
+       }
+       // Compute how much of the stack is currently in use and only
+       // shrink the stack if gp is using less than a quarter of its
+       // current stack. The currently used stack includes everything
+       // down to the SP plus the stack guard space that ensures
+       // there's room for nosplit functions.
+       avail := gp.stack.hi - gp.stack.lo
+       if used := gp.stack.hi - gp.sched.sp + _StackLimit; used >= avail/4 {
+               return
+       }
+
+       // We can't copy the stack if we're in a syscall.
+       // The syscall might have pointers into the stack.
+       if gp.syscallsp != 0 {
+               return
+       }
+       if sys.GoosWindows != 0 && gp.m != nil && gp.m.libcallsp != 0 {
+               return
+       }
+
+       if stackDebug > 0 {
+               print("shrinking stack ", oldsize, "->", newsize, "\n")
+       }
+
+       oldstatus := casgcopystack(gp)
+       copystack(gp, newsize)
+       casgstatus(gp, _Gcopystack, oldstatus)
+}
+
+// freeStackSpans frees unused stack spans at the end of GC.
+func freeStackSpans() {
+       lock(&stackpoolmu)
+
+       // Scan stack pools for empty stack spans.
+       for order := range stackpool {
+               list := &stackpool[order]
+               for s := list.first; s != nil; {
+                       next := s.next
+                       if s.ref == 0 {
+                               list.remove(s)
+                               s.freelist = 0
+                               mheap_.freeStack(s)
+                       }
+                       s = next
+               }
+       }
+
+       unlock(&stackpoolmu)
+
+       // Free large stack spans.
+       lock(&stackLarge.lock)
+       for i := range stackLarge.free {
+               for s := stackLarge.free[i].first; s != nil; {
+                       next := s.next
+                       stackLarge.free[i].remove(s)
+                       mheap_.freeStack(s)
+                       s = next
+               }
+       }
+       unlock(&stackLarge.lock)
+}
+
+//go:nosplit
+func morestackc() {
+       systemstack(func() {
+               throw("attempt to execute C code on Go stack")
+       })
+}
index 71bd8307dfd1c7532b24be6d28fc7cd28d6baa1f..e0967b336c41c4e514a24b7903b154d9a3712335 100644 (file)
@@ -126,7 +126,7 @@ func TestStringW(t *testing.T) {
 */
 
 func TestLargeStringConcat(t *testing.T) {
-       output := executeTest(t, largeStringConcatSource, nil)
+       output := runTestProg(t, "testprog", "stringconcat")
        want := "panic: " + strings.Repeat("0", 1<<10) + strings.Repeat("1", 1<<10) +
                strings.Repeat("2", 1<<10) + strings.Repeat("3", 1<<10)
        if !strings.HasPrefix(output, want) {
@@ -134,19 +134,6 @@ func TestLargeStringConcat(t *testing.T) {
        }
 }
 
-var largeStringConcatSource = `
-package main
-import "strings"
-func main() {
-       s0 := strings.Repeat("0", 1<<10)
-       s1 := strings.Repeat("1", 1<<10)
-       s2 := strings.Repeat("2", 1<<10)
-       s3 := strings.Repeat("3", 1<<10)
-       s := s0 + s1 + s2 + s3
-       panic(s)
-}
-`
-
 /*
 func TestGostringnocopy(t *testing.T) {
        max := *runtime.Maxstring
diff --git a/libgo/go/runtime/sys_mips64x.go b/libgo/go/runtime/sys_mips64x.go
new file mode 100644 (file)
index 0000000..9e7d805
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2015 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 mips64 mips64le
+
+package runtime
+
+import "unsafe"
+
+// adjust Gobuf as if it executed a call to fn with context ctxt
+// and then did an immediate Gosave.
+func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
+       if buf.lr != 0 {
+               throw("invalid use of gostartcall")
+       }
+       buf.lr = buf.pc
+       buf.pc = uintptr(fn)
+       buf.ctxt = ctxt
+}
+
+// Called to rewind context saved during morestack back to beginning of function.
+// To help us, the linker emits a jmp back to the beginning right after the
+// call to morestack. We just have to decode and apply that jump.
+func rewindmorestack(buf *gobuf) {
+       var inst uint32
+       if buf.pc&3 == 0 && buf.pc != 0 {
+               inst = *(*uint32)(unsafe.Pointer(buf.pc))
+               if inst>>26 == 2 { // JMP addr
+                       //print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(buf.pc &^ uintptr(1<<28-1) | uintptr((inst&^0xfc000000)<<2)), "\n");
+                       buf.pc &^= 1<<28 - 1
+                       buf.pc |= uintptr((inst &^ 0xfc000000) << 2)
+                       return
+               }
+               if inst>>16 == 0x1000 { // BEQ  R0, R0, offset
+                       //print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(buf.pc + uintptr(int32(int16(inst&0xffff))<<2 + 4)), "\n");
+                       buf.pc += uintptr(int32(int16(inst&0xffff))<<2 + 4)
+                       return
+               }
+       }
+       print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
+       throw("runtime: misuse of rewindmorestack")
+}
similarity index 67%
rename from libgo/go/fmt/norace_test.go
rename to libgo/go/runtime/sys_nonppc64x.go
index 1267cc34ee332a87114b1d6213b0afab7de5436b..440937498f72eda623fcdc9ebde45ba51ea50d66 100644 (file)
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !race
+// +build !ppc64,!ppc64le
 
-package fmt_test
+package runtime
 
-const raceenabled = false
+func prepGoExitFrame(sp uintptr) {
+}
diff --git a/libgo/go/runtime/testdata/testprog/crash.go b/libgo/go/runtime/testdata/testprog/crash.go
new file mode 100644 (file)
index 0000000..3d7c7c6
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright 2015 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 main
+
+import (
+       "fmt"
+       "runtime"
+)
+
+func init() {
+       register("Crash", Crash)
+}
+
+func test(name string) {
+       defer func() {
+               if x := recover(); x != nil {
+                       fmt.Printf(" recovered")
+               }
+               fmt.Printf(" done\n")
+       }()
+       fmt.Printf("%s:", name)
+       var s *string
+       _ = *s
+       fmt.Print("SHOULD NOT BE HERE")
+}
+
+func testInNewThread(name string) {
+       c := make(chan bool)
+       go func() {
+               runtime.LockOSThread()
+               test(name)
+               c <- true
+       }()
+       <-c
+}
+
+func Crash() {
+       runtime.LockOSThread()
+       test("main")
+       testInNewThread("new-thread")
+       testInNewThread("second-new-thread")
+       test("main-again")
+}
diff --git a/libgo/go/runtime/testdata/testprog/deadlock.go b/libgo/go/runtime/testdata/testprog/deadlock.go
new file mode 100644 (file)
index 0000000..7f0a0cd
--- /dev/null
@@ -0,0 +1,173 @@
+// Copyright 2015 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 main
+
+import (
+       "fmt"
+       "runtime"
+       "runtime/debug"
+       "time"
+)
+
+func init() {
+       registerInit("InitDeadlock", InitDeadlock)
+       registerInit("NoHelperGoroutines", NoHelperGoroutines)
+
+       register("SimpleDeadlock", SimpleDeadlock)
+       register("LockedDeadlock", LockedDeadlock)
+       register("LockedDeadlock2", LockedDeadlock2)
+       register("GoexitDeadlock", GoexitDeadlock)
+       register("StackOverflow", StackOverflow)
+       register("ThreadExhaustion", ThreadExhaustion)
+       register("RecursivePanic", RecursivePanic)
+       register("GoexitExit", GoexitExit)
+       register("GoNil", GoNil)
+       register("MainGoroutineID", MainGoroutineID)
+       register("Breakpoint", Breakpoint)
+       register("GoexitInPanic", GoexitInPanic)
+       register("PanicAfterGoexit", PanicAfterGoexit)
+       register("RecoveredPanicAfterGoexit", RecoveredPanicAfterGoexit)
+
+}
+
+func SimpleDeadlock() {
+       select {}
+       panic("not reached")
+}
+
+func InitDeadlock() {
+       select {}
+       panic("not reached")
+}
+
+func LockedDeadlock() {
+       runtime.LockOSThread()
+       select {}
+}
+
+func LockedDeadlock2() {
+       go func() {
+               runtime.LockOSThread()
+               select {}
+       }()
+       time.Sleep(time.Millisecond)
+       select {}
+}
+
+func GoexitDeadlock() {
+       F := func() {
+               for i := 0; i < 10; i++ {
+               }
+       }
+
+       go F()
+       go F()
+       runtime.Goexit()
+}
+
+func StackOverflow() {
+       var f func() byte
+       f = func() byte {
+               var buf [64 << 10]byte
+               return buf[0] + f()
+       }
+       debug.SetMaxStack(1474560)
+       f()
+}
+
+func ThreadExhaustion() {
+       debug.SetMaxThreads(10)
+       c := make(chan int)
+       for i := 0; i < 100; i++ {
+               go func() {
+                       runtime.LockOSThread()
+                       c <- 0
+                       select {}
+               }()
+               <-c
+       }
+}
+
+func RecursivePanic() {
+       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")
+}
+
+func GoexitExit() {
+       go func() {
+               time.Sleep(time.Millisecond)
+       }()
+       i := 0
+       runtime.SetFinalizer(&i, func(p *int) {})
+       runtime.GC()
+       runtime.Goexit()
+}
+
+func GoNil() {
+       defer func() {
+               recover()
+       }()
+       var f func()
+       go f()
+       select {}
+}
+
+func MainGoroutineID() {
+       panic("test")
+}
+
+func NoHelperGoroutines() {
+       i := 0
+       runtime.SetFinalizer(&i, func(p *int) {})
+       time.AfterFunc(time.Hour, func() {})
+       panic("oops")
+}
+
+func Breakpoint() {
+       runtime.Breakpoint()
+}
+
+func GoexitInPanic() {
+       go func() {
+               defer func() {
+                       runtime.Goexit()
+               }()
+               panic("hello")
+       }()
+       runtime.Goexit()
+}
+
+func PanicAfterGoexit() {
+       defer func() {
+               panic("hello")
+       }()
+       runtime.Goexit()
+}
+
+func RecoveredPanicAfterGoexit() {
+       defer func() {
+               defer func() {
+                       r := recover()
+                       if r == nil {
+                               panic("bad recover")
+                       }
+               }()
+               panic("hello")
+       }()
+       runtime.Goexit()
+}
diff --git a/libgo/go/runtime/testdata/testprog/gc.go b/libgo/go/runtime/testdata/testprog/gc.go
new file mode 100644 (file)
index 0000000..9bb367c
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2015 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 main
+
+import (
+       "fmt"
+       "os"
+       "runtime"
+       "time"
+)
+
+func init() {
+       register("GCFairness", GCFairness)
+       register("GCSys", GCSys)
+}
+
+func GCSys() {
+       runtime.GOMAXPROCS(1)
+       memstats := new(runtime.MemStats)
+       runtime.GC()
+       runtime.ReadMemStats(memstats)
+       sys := memstats.Sys
+
+       runtime.MemProfileRate = 0 // disable profiler
+
+       itercount := 100000
+       for i := 0; i < itercount; i++ {
+               workthegc()
+       }
+
+       // Should only be using a few MB.
+       // We allocated 100 MB or (if not short) 1 GB.
+       runtime.ReadMemStats(memstats)
+       if sys > memstats.Sys {
+               sys = 0
+       } else {
+               sys = memstats.Sys - sys
+       }
+       if sys > 16<<20 {
+               fmt.Printf("using too much memory: %d bytes\n", sys)
+               return
+       }
+       fmt.Printf("OK\n")
+}
+
+func workthegc() []byte {
+       return make([]byte, 1029)
+}
+
+func GCFairness() {
+       runtime.GOMAXPROCS(1)
+       f, err := os.Open("/dev/null")
+       if os.IsNotExist(err) {
+               // This test tests what it is intended to test only if writes are fast.
+               // If there is no /dev/null, we just don't execute the test.
+               fmt.Println("OK")
+               return
+       }
+       if err != nil {
+               fmt.Println(err)
+               os.Exit(1)
+       }
+       for i := 0; i < 2; i++ {
+               go func() {
+                       for {
+                               f.Write([]byte("."))
+                       }
+               }()
+       }
+       time.Sleep(10 * time.Millisecond)
+       fmt.Println("OK")
+}
diff --git a/libgo/go/runtime/testdata/testprog/main.go b/libgo/go/runtime/testdata/testprog/main.go
new file mode 100644 (file)
index 0000000..9c227bb
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2015 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 main
+
+import "os"
+
+var cmds = map[string]func(){}
+
+func register(name string, f func()) {
+       if cmds[name] != nil {
+               panic("duplicate registration: " + name)
+       }
+       cmds[name] = f
+}
+
+func registerInit(name string, f func()) {
+       if len(os.Args) >= 2 && os.Args[1] == name {
+               f()
+       }
+}
+
+func main() {
+       if len(os.Args) < 2 {
+               println("usage: " + os.Args[0] + " name-of-test")
+               return
+       }
+       f := cmds[os.Args[1]]
+       if f == nil {
+               println("unknown function: " + os.Args[1])
+               return
+       }
+       f()
+}
diff --git a/libgo/go/runtime/testdata/testprog/misc.go b/libgo/go/runtime/testdata/testprog/misc.go
new file mode 100644 (file)
index 0000000..237680f
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2016 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "runtime"
+
+func init() {
+       register("NumGoroutine", NumGoroutine)
+}
+
+func NumGoroutine() {
+       println(runtime.NumGoroutine())
+}
diff --git a/libgo/go/runtime/testdata/testprog/signal.go b/libgo/go/runtime/testdata/testprog/signal.go
new file mode 100644 (file)
index 0000000..ac2d3e8
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2015 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 !windows,!plan9,!nacl
+
+package main
+
+import "syscall"
+
+func init() {
+       register("SignalExitStatus", SignalExitStatus)
+}
+
+func SignalExitStatus() {
+       syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
+}
diff --git a/libgo/go/runtime/testdata/testprog/stringconcat.go b/libgo/go/runtime/testdata/testprog/stringconcat.go
new file mode 100644 (file)
index 0000000..9dddf19
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2015 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 main
+
+import "strings"
+
+func init() {
+       register("stringconcat", stringconcat)
+}
+
+func stringconcat() {
+       s0 := strings.Repeat("0", 1<<10)
+       s1 := strings.Repeat("1", 1<<10)
+       s2 := strings.Repeat("2", 1<<10)
+       s3 := strings.Repeat("3", 1<<10)
+       s := s0 + s1 + s2 + s3
+       panic(s)
+}
diff --git a/libgo/go/runtime/testdata/testprog/syscall_windows.go b/libgo/go/runtime/testdata/testprog/syscall_windows.go
new file mode 100644 (file)
index 0000000..73165be
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2015 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 main
+
+import "syscall"
+
+func init() {
+       register("RaiseException", RaiseException)
+       register("ZeroDivisionException", ZeroDivisionException)
+}
+
+func RaiseException() {
+       const EXCEPTION_NONCONTINUABLE = 1
+       mod := syscall.MustLoadDLL("kernel32.dll")
+       proc := mod.MustFindProc("RaiseException")
+       proc.Call(0xbad, EXCEPTION_NONCONTINUABLE, 0, 0)
+       println("RaiseException should not return")
+}
+
+func ZeroDivisionException() {
+       x := 1
+       y := 0
+       z := x / y
+       println(z)
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/callback.go b/libgo/go/runtime/testdata/testprogcgo/callback.go
new file mode 100644 (file)
index 0000000..10e248a
--- /dev/null
@@ -0,0 +1,89 @@
+// Copyright 2015 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 !plan9,!windows
+
+package main
+
+/*
+#include <pthread.h>
+
+void go_callback();
+
+static void *thr(void *arg) {
+    go_callback();
+    return 0;
+}
+
+static void foo() {
+    pthread_t th;
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setstacksize(&attr, 256 << 10);
+    pthread_create(&th, &attr, thr, 0);
+    pthread_join(th, 0);
+}
+*/
+import "C"
+
+import (
+       "fmt"
+       "runtime"
+)
+
+func init() {
+       register("CgoCallbackGC", CgoCallbackGC)
+}
+
+//export go_callback
+func go_callback() {
+       runtime.GC()
+       grow()
+       runtime.GC()
+}
+
+var cnt int
+
+func grow() {
+       x := 10000
+       sum := 0
+       if grow1(&x, &sum) == 0 {
+               panic("bad")
+       }
+}
+
+func grow1(x, sum *int) int {
+       if *x == 0 {
+               return *sum + 1
+       }
+       *x--
+       sum1 := *sum + *x
+       return grow1(x, &sum1)
+}
+
+func CgoCallbackGC() {
+       const P = 100
+       done := make(chan bool)
+       // allocate a bunch of stack frames and spray them with pointers
+       for i := 0; i < P; i++ {
+               go func() {
+                       grow()
+                       done <- true
+               }()
+       }
+       for i := 0; i < P; i++ {
+               <-done
+       }
+       // now give these stack frames to cgo callbacks
+       for i := 0; i < P; i++ {
+               go func() {
+                       C.foo()
+                       done <- true
+               }()
+       }
+       for i := 0; i < P; i++ {
+               <-done
+       }
+       fmt.Printf("OK\n")
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/cgo.go b/libgo/go/runtime/testdata/testprogcgo/cgo.go
new file mode 100644 (file)
index 0000000..cf1af82
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright 2015 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 main
+
+/*
+void foo1(void) {}
+*/
+import "C"
+import (
+       "fmt"
+       "runtime"
+       "time"
+)
+
+func init() {
+       register("CgoSignalDeadlock", CgoSignalDeadlock)
+       register("CgoTraceback", CgoTraceback)
+}
+
+func CgoSignalDeadlock() {
+       runtime.GOMAXPROCS(100)
+       ping := make(chan bool)
+       go func() {
+               for i := 0; ; i++ {
+                       runtime.Gosched()
+                       select {
+                       case done := <-ping:
+                               if done {
+                                       ping <- true
+                                       return
+                               }
+                               ping <- true
+                       default:
+                       }
+                       func() {
+                               defer func() {
+                                       recover()
+                               }()
+                               var s *string
+                               *s = ""
+                       }()
+               }
+       }()
+       time.Sleep(time.Millisecond)
+       for i := 0; i < 64; i++ {
+               go func() {
+                       runtime.LockOSThread()
+                       select {}
+               }()
+               go func() {
+                       runtime.LockOSThread()
+                       select {}
+               }()
+               time.Sleep(time.Millisecond)
+               ping <- false
+               select {
+               case <-ping:
+               case <-time.After(time.Second):
+                       fmt.Printf("HANG\n")
+                       return
+               }
+       }
+       ping <- true
+       select {
+       case <-ping:
+       case <-time.After(time.Second):
+               fmt.Printf("HANG\n")
+               return
+       }
+       fmt.Printf("OK\n")
+}
+
+func CgoTraceback() {
+       C.foo1()
+       buf := make([]byte, 1)
+       runtime.Stack(buf, true)
+       fmt.Printf("OK\n")
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/crash.go b/libgo/go/runtime/testdata/testprogcgo/crash.go
new file mode 100644 (file)
index 0000000..3d7c7c6
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright 2015 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 main
+
+import (
+       "fmt"
+       "runtime"
+)
+
+func init() {
+       register("Crash", Crash)
+}
+
+func test(name string) {
+       defer func() {
+               if x := recover(); x != nil {
+                       fmt.Printf(" recovered")
+               }
+               fmt.Printf(" done\n")
+       }()
+       fmt.Printf("%s:", name)
+       var s *string
+       _ = *s
+       fmt.Print("SHOULD NOT BE HERE")
+}
+
+func testInNewThread(name string) {
+       c := make(chan bool)
+       go func() {
+               runtime.LockOSThread()
+               test(name)
+               c <- true
+       }()
+       <-c
+}
+
+func Crash() {
+       runtime.LockOSThread()
+       test("main")
+       testInNewThread("new-thread")
+       testInNewThread("second-new-thread")
+       test("main-again")
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/dll_windows.go b/libgo/go/runtime/testdata/testprogcgo/dll_windows.go
new file mode 100644 (file)
index 0000000..a0647ef
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2015 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 main
+
+/*
+#include <windows.h>
+
+DWORD getthread() {
+       return GetCurrentThreadId();
+}
+*/
+import "C"
+import "./windows"
+
+func init() {
+       register("CgoDLLImportsMain", CgoDLLImportsMain)
+}
+
+func CgoDLLImportsMain() {
+       C.getthread()
+       windows.GetThread()
+       println("OK")
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/dropm.go b/libgo/go/runtime/testdata/testprogcgo/dropm.go
new file mode 100644 (file)
index 0000000..75984ea
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright 2016 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9,!windows
+
+// Test that a sequence of callbacks from C to Go get the same m.
+// This failed to be true on arm and arm64, which was the root cause
+// of issue 13881.
+
+package main
+
+/*
+#include <stddef.h>
+#include <pthread.h>
+
+extern void GoCheckM();
+
+static void* thread(void* arg __attribute__ ((unused))) {
+       GoCheckM();
+       return NULL;
+}
+
+static void CheckM() {
+       pthread_t tid;
+       pthread_create(&tid, NULL, thread, NULL);
+       pthread_join(tid, NULL);
+       pthread_create(&tid, NULL, thread, NULL);
+       pthread_join(tid, NULL);
+}
+*/
+import "C"
+
+import (
+       "fmt"
+       "os"
+)
+
+func init() {
+       register("EnsureDropM", EnsureDropM)
+}
+
+var savedM uintptr
+
+//export GoCheckM
+func GoCheckM() {
+       m := runtime_getm_for_test()
+       if savedM == 0 {
+               savedM = m
+       } else if savedM != m {
+               fmt.Printf("m == %x want %x\n", m, savedM)
+               os.Exit(1)
+       }
+}
+
+func EnsureDropM() {
+       C.CheckM()
+       fmt.Println("OK")
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/dropm_stub.go b/libgo/go/runtime/testdata/testprogcgo/dropm_stub.go
new file mode 100644 (file)
index 0000000..4c3f46a
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import _ "unsafe" // for go:linkname
+
+// Defined in the runtime package.
+//go:linkname runtime_getm_for_test runtime.getm
+func runtime_getm_for_test() uintptr
diff --git a/libgo/go/runtime/testdata/testprogcgo/exec.go b/libgo/go/runtime/testdata/testprogcgo/exec.go
new file mode 100644 (file)
index 0000000..8dc1d51
--- /dev/null
@@ -0,0 +1,89 @@
+// Copyright 2015 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 !plan9,!windows
+
+package main
+
+/*
+#include <stddef.h>
+#include <signal.h>
+#include <pthread.h>
+
+// Save the signal mask at startup so that we see what it is before
+// the Go runtime starts setting up signals.
+
+static sigset_t mask;
+
+static void init(void) __attribute__ ((constructor));
+
+static void init() {
+       sigemptyset(&mask);
+       pthread_sigmask(SIG_SETMASK, NULL, &mask);
+}
+
+int SIGINTBlocked() {
+       return sigismember(&mask, SIGINT);
+}
+*/
+import "C"
+
+import (
+       "fmt"
+       "os"
+       "os/exec"
+       "os/signal"
+       "sync"
+       "syscall"
+)
+
+func init() {
+       register("CgoExecSignalMask", CgoExecSignalMask)
+}
+
+func CgoExecSignalMask() {
+       if len(os.Args) > 2 && os.Args[2] == "testsigint" {
+               if C.SIGINTBlocked() != 0 {
+                       os.Exit(1)
+               }
+               os.Exit(0)
+       }
+
+       c := make(chan os.Signal, 1)
+       signal.Notify(c, syscall.SIGTERM)
+       go func() {
+               for range c {
+               }
+       }()
+
+       const goCount = 10
+       const execCount = 10
+       var wg sync.WaitGroup
+       wg.Add(goCount*execCount + goCount)
+       for i := 0; i < goCount; i++ {
+               go func() {
+                       defer wg.Done()
+                       for j := 0; j < execCount; j++ {
+                               c2 := make(chan os.Signal, 1)
+                               signal.Notify(c2, syscall.SIGUSR1)
+                               syscall.Kill(os.Getpid(), syscall.SIGTERM)
+                               go func(j int) {
+                                       defer wg.Done()
+                                       cmd := exec.Command(os.Args[0], "CgoExecSignalMask", "testsigint")
+                                       cmd.Stdin = os.Stdin
+                                       cmd.Stdout = os.Stdout
+                                       cmd.Stderr = os.Stderr
+                                       if err := cmd.Run(); err != nil {
+                                               fmt.Printf("iteration %d: %v\n", j, err)
+                                               os.Exit(1)
+                                       }
+                               }(j)
+                               signal.Stop(c2)
+                       }
+               }()
+       }
+       wg.Wait()
+
+       fmt.Println("OK")
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/main.go b/libgo/go/runtime/testdata/testprogcgo/main.go
new file mode 100644 (file)
index 0000000..9c227bb
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2015 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 main
+
+import "os"
+
+var cmds = map[string]func(){}
+
+func register(name string, f func()) {
+       if cmds[name] != nil {
+               panic("duplicate registration: " + name)
+       }
+       cmds[name] = f
+}
+
+func registerInit(name string, f func()) {
+       if len(os.Args) >= 2 && os.Args[1] == name {
+               f()
+       }
+}
+
+func main() {
+       if len(os.Args) < 2 {
+               println("usage: " + os.Args[0] + " name-of-test")
+               return
+       }
+       f := cmds[os.Args[1]]
+       if f == nil {
+               println("unknown function: " + os.Args[1])
+               return
+       }
+       f()
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/threadpanic.go b/libgo/go/runtime/testdata/testprogcgo/threadpanic.go
new file mode 100644 (file)
index 0000000..3c9baba
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2015 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 !plan9
+
+package main
+
+// void start(void);
+import "C"
+
+func init() {
+       register("CgoExternalThreadPanic", CgoExternalThreadPanic)
+}
+
+func CgoExternalThreadPanic() {
+       C.start()
+       select {}
+}
+
+//export gopanic
+func gopanic() {
+       panic("BOOM")
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/threadprof.go b/libgo/go/runtime/testdata/testprogcgo/threadprof.go
new file mode 100644 (file)
index 0000000..03e35d2
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2015 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 !plan9,!windows
+
+package main
+
+/*
+#include <stdint.h>
+#include <signal.h>
+#include <pthread.h>
+
+volatile int32_t spinlock;
+
+static void *thread1(void *p) {
+       (void)p;
+       while (spinlock == 0)
+               ;
+       pthread_kill(pthread_self(), SIGPROF);
+       spinlock = 0;
+       return NULL;
+}
+__attribute__((constructor)) void issue9456() {
+       pthread_t tid;
+       pthread_create(&tid, 0, thread1, NULL);
+}
+
+void **nullptr;
+
+void *crash(void *p) {
+       *nullptr = p;
+       return 0;
+}
+
+int start_crashing_thread(void) {
+       pthread_t tid;
+       return pthread_create(&tid, 0, crash, 0);
+}
+*/
+import "C"
+
+import (
+       "fmt"
+       "os"
+       "os/exec"
+       "runtime"
+       "sync/atomic"
+       "time"
+       "unsafe"
+)
+
+func init() {
+       register("CgoExternalThreadSIGPROF", CgoExternalThreadSIGPROF)
+       register("CgoExternalThreadSignal", CgoExternalThreadSignal)
+}
+
+func CgoExternalThreadSIGPROF() {
+       // This test intends to test that sending SIGPROF to foreign threads
+       // before we make any cgo call will not abort the whole process, so
+       // we cannot make any cgo call here. See https://golang.org/issue/9456.
+       atomic.StoreInt32((*int32)(unsafe.Pointer(&C.spinlock)), 1)
+       for atomic.LoadInt32((*int32)(unsafe.Pointer(&C.spinlock))) == 1 {
+               runtime.Gosched()
+       }
+       println("OK")
+}
+
+func CgoExternalThreadSignal() {
+       if len(os.Args) > 2 && os.Args[2] == "crash" {
+               i := C.start_crashing_thread()
+               if i != 0 {
+                       fmt.Println("pthread_create failed:", i)
+                       // Exit with 0 because parent expects us to crash.
+                       return
+               }
+
+               // We should crash immediately, but give it plenty of
+               // time before failing (by exiting 0) in case we are
+               // running on a slow system.
+               time.Sleep(5 * time.Second)
+               return
+       }
+
+       out, err := exec.Command(os.Args[0], "CgoExternalThreadSignal", "crash").CombinedOutput()
+       if err == nil {
+               fmt.Println("C signal did not crash as expected\n")
+               fmt.Printf("%s\n", out)
+               os.Exit(1)
+       }
+
+       fmt.Println("OK")
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/windows/win.go b/libgo/go/runtime/testdata/testprogcgo/windows/win.go
new file mode 100644 (file)
index 0000000..f2eabb9
--- /dev/null
@@ -0,0 +1,16 @@
+package windows
+
+/*
+#cgo CFLAGS: -mnop-fun-dllimport
+
+#include <windows.h>
+
+DWORD agetthread() {
+       return GetCurrentThreadId();
+}
+*/
+import "C"
+
+func GetThread() uint32 {
+       return uint32(C.agetthread())
+}
diff --git a/libgo/go/runtime/testdata/testprognet/main.go b/libgo/go/runtime/testdata/testprognet/main.go
new file mode 100644 (file)
index 0000000..9c227bb
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2015 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 main
+
+import "os"
+
+var cmds = map[string]func(){}
+
+func register(name string, f func()) {
+       if cmds[name] != nil {
+               panic("duplicate registration: " + name)
+       }
+       cmds[name] = f
+}
+
+func registerInit(name string, f func()) {
+       if len(os.Args) >= 2 && os.Args[1] == name {
+               f()
+       }
+}
+
+func main() {
+       if len(os.Args) < 2 {
+               println("usage: " + os.Args[0] + " name-of-test")
+               return
+       }
+       f := cmds[os.Args[1]]
+       if f == nil {
+               println("unknown function: " + os.Args[1])
+               return
+       }
+       f()
+}
diff --git a/libgo/go/runtime/testdata/testprognet/net.go b/libgo/go/runtime/testdata/testprognet/net.go
new file mode 100644 (file)
index 0000000..c1a7f3f
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2015 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 main
+
+import (
+       "fmt"
+       "net"
+)
+
+func init() {
+       registerInit("NetpollDeadlock", NetpollDeadlockInit)
+       register("NetpollDeadlock", NetpollDeadlock)
+}
+
+func NetpollDeadlockInit() {
+       fmt.Println("dialing")
+       c, err := net.Dial("tcp", "localhost:14356")
+       if err == nil {
+               c.Close()
+       } else {
+               fmt.Println("error: ", err)
+       }
+}
+
+func NetpollDeadlock() {
+       fmt.Println("done")
+}
diff --git a/libgo/go/runtime/testdata/testprognet/signal.go b/libgo/go/runtime/testdata/testprognet/signal.go
new file mode 100644 (file)
index 0000000..24d1424
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2016 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !windows,!plan9,!nacl
+
+// This is in testprognet instead of testprog because testprog
+// must not import anything (like net, but also like os/signal)
+// that kicks off background goroutines during init.
+
+package main
+
+import (
+       "os/signal"
+       "syscall"
+)
+
+func init() {
+       register("SignalIgnoreSIGTRAP", SignalIgnoreSIGTRAP)
+}
+
+func SignalIgnoreSIGTRAP() {
+       signal.Ignore(syscall.SIGTRAP)
+       syscall.Kill(syscall.Getpid(), syscall.SIGTRAP)
+       println("OK")
+}
diff --git a/libgo/go/runtime/write_err.go b/libgo/go/runtime/write_err.go
new file mode 100644 (file)
index 0000000..6b1467b
--- /dev/null
@@ -0,0 +1,13 @@
+// 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 !android
+
+package runtime
+
+import "unsafe"
+
+func writeErr(b []byte) {
+       write(2, unsafe.Pointer(&b[0]), int32(len(b)))
+}
diff --git a/libgo/go/runtime/write_err_android.go b/libgo/go/runtime/write_err_android.go
new file mode 100644 (file)
index 0000000..4411a14
--- /dev/null
@@ -0,0 +1,160 @@
+// 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 runtime
+
+import "unsafe"
+
+var (
+       writeHeader = []byte{6 /* ANDROID_LOG_ERROR */, 'G', 'o', 0}
+       writePath   = []byte("/dev/log/main\x00")
+       writeLogd   = []byte("/dev/socket/logdw\x00")
+
+       // guarded by printlock/printunlock.
+       writeFD  uintptr
+       writeBuf [1024]byte
+       writePos int
+)
+
+// Prior to Android-L, logging was done through writes to /dev/log files implemented
+// in kernel ring buffers. In Android-L, those /dev/log files are no longer
+// accessible and logging is done through a centralized user-mode logger, logd.
+//
+// https://android.googlesource.com/platform/system/core/+/master/liblog/logd_write.c
+type loggerType int32
+
+const (
+       unknown loggerType = iota
+       legacy
+       logd
+       // TODO(hakim): logging for emulator?
+)
+
+var logger loggerType
+
+func writeErr(b []byte) {
+       if logger == unknown {
+               // Use logd if /dev/socket/logdw is available.
+               if v := uintptr(access(&writeLogd[0], 0x02 /* W_OK */)); v == 0 {
+                       logger = logd
+                       initLogd()
+               } else {
+                       logger = legacy
+                       initLegacy()
+               }
+       }
+
+       // Write to stderr for command-line programs.
+       write(2, unsafe.Pointer(&b[0]), int32(len(b)))
+
+       // Log format: "<header>\x00<message m bytes>\x00"
+       //
+       // <header>
+       //   In legacy mode: "<priority 1 byte><tag n bytes>".
+       //   In logd mode: "<android_log_header_t 11 bytes><priority 1 byte><tag n bytes>"
+       //
+       // The entire log needs to be delivered in a single syscall (the NDK
+       // does this with writev). Each log is its own line, so we need to
+       // buffer writes until we see a newline.
+       var hlen int
+       switch logger {
+       case logd:
+               hlen = writeLogdHeader()
+       case legacy:
+               hlen = len(writeHeader)
+       }
+
+       dst := writeBuf[hlen:]
+       for _, v := range b {
+               if v == 0 { // android logging won't print a zero byte
+                       v = '0'
+               }
+               dst[writePos] = v
+               writePos++
+               if v == '\n' || writePos == len(dst)-1 {
+                       dst[writePos] = 0
+                       write(writeFD, unsafe.Pointer(&writeBuf[0]), int32(hlen+writePos))
+                       memclrBytes(dst)
+                       writePos = 0
+               }
+       }
+}
+
+func initLegacy() {
+       // In legacy mode, logs are written to /dev/log/main
+       writeFD = uintptr(open(&writePath[0], 0x1 /* O_WRONLY */, 0))
+       if writeFD == 0 {
+               // It is hard to do anything here. Write to stderr just
+               // in case user has root on device and has run
+               //      adb shell setprop log.redirect-stdio true
+               msg := []byte("runtime: cannot open /dev/log/main\x00")
+               write(2, unsafe.Pointer(&msg[0]), int32(len(msg)))
+               exit(2)
+       }
+
+       // Prepopulate the invariant header part.
+       copy(writeBuf[:len(writeHeader)], writeHeader)
+}
+
+// used in initLogdWrite but defined here to avoid heap allocation.
+var logdAddr sockaddr_un
+
+func initLogd() {
+       // In logd mode, logs are sent to the logd via a unix domain socket.
+       logdAddr.family = _AF_UNIX
+       copy(logdAddr.path[:], writeLogd)
+
+       // We are not using non-blocking I/O because writes taking this path
+       // are most likely triggered by panic, we cannot think of the advantage of
+       // non-blocking I/O for panic but see disadvantage (dropping panic message),
+       // and blocking I/O simplifies the code a lot.
+       fd := socket(_AF_UNIX, _SOCK_DGRAM|_O_CLOEXEC, 0)
+       if fd < 0 {
+               msg := []byte("runtime: cannot create a socket for logging\x00")
+               write(2, unsafe.Pointer(&msg[0]), int32(len(msg)))
+               exit(2)
+       }
+
+       errno := connect(fd, unsafe.Pointer(&logdAddr), int32(unsafe.Sizeof(logdAddr)))
+       if errno < 0 {
+               msg := []byte("runtime: cannot connect to /dev/socket/logdw\x00")
+               write(2, unsafe.Pointer(&msg[0]), int32(len(msg)))
+               // TODO(hakim): or should we just close fd and hope for better luck next time?
+               exit(2)
+       }
+       writeFD = uintptr(fd)
+
+       // Prepopulate invariant part of the header.
+       // The first 11 bytes will be populated later in writeLogdHeader.
+       copy(writeBuf[11:11+len(writeHeader)], writeHeader)
+}
+
+// writeLogdHeader populates the header and returns the length of the payload.
+func writeLogdHeader() int {
+       hdr := writeBuf[:11]
+
+       // The first 11 bytes of the header corresponds to android_log_header_t
+       // as defined in system/core/include/private/android_logger.h
+       //   hdr[0] log type id (unsigned char), defined in <log/log.h>
+       //   hdr[1:2] tid (uint16_t)
+       //   hdr[3:11] log_time defined in <log/log_read.h>
+       //      hdr[3:7] sec unsigned uint32, little endian.
+       //      hdr[7:11] nsec unsigned uint32, little endian.
+       hdr[0] = 0 // LOG_ID_MAIN
+       sec, nsec := time_now()
+       packUint32(hdr[3:7], uint32(sec))
+       packUint32(hdr[7:11], uint32(nsec))
+
+       // TODO(hakim):  hdr[1:2] = gettid?
+
+       return 11 + len(writeHeader)
+}
+
+func packUint32(b []byte, v uint32) {
+       // little-endian.
+       b[0] = byte(v)
+       b[1] = byte(v >> 8)
+       b[2] = byte(v >> 16)
+       b[3] = byte(v >> 24)
+}
index ac316540fd58aad5ddbf4f63e9f69a9baf7c9700..40d12152ce28c111af0d083a9a0b05320d6b8bd0 100644 (file)
@@ -122,10 +122,10 @@ func Example_sortMultiKeys() {
        fmt.Println("By language,<lines,user:", changes)
 
        // Output:
-       // By user: [{dmr C 100} {glenda Go 200} {gri Smalltalk 80} {gri Go 100} {ken Go 200} {ken C 150} {r Go 100} {r C 150} {rsc Go 200}]
+       // By user: [{dmr C 100} {glenda Go 200} {gri Go 100} {gri Smalltalk 80} {ken C 150} {ken Go 200} {r Go 100} {r C 150} {rsc Go 200}]
        // By user,<lines: [{dmr C 100} {glenda Go 200} {gri Smalltalk 80} {gri Go 100} {ken C 150} {ken Go 200} {r Go 100} {r C 150} {rsc Go 200}]
        // By user,>lines: [{dmr C 100} {glenda Go 200} {gri Go 100} {gri Smalltalk 80} {ken Go 200} {ken C 150} {r C 150} {r Go 100} {rsc Go 200}]
-       // By language,<lines: [{dmr C 100} {ken C 150} {r C 150} {gri Go 100} {r Go 100} {ken Go 200} {glenda Go 200} {rsc Go 200} {gri Smalltalk 80}]
+       // By language,<lines: [{dmr C 100} {ken C 150} {r C 150} {r Go 100} {gri Go 100} {ken Go 200} {glenda Go 200} {rsc Go 200} {gri Smalltalk 80}]
        // By language,<lines,user: [{dmr C 100} {ken C 150} {r C 150} {gri Go 100} {r Go 100} {glenda Go 200} {ken Go 200} {rsc Go 200} {gri Smalltalk 80}]
 
 }
index 8a2c1c33b14b36013925f74e6e560aca2d1b3c21..de8178ff484ef43f4a01281a243857bbb5a83cbd 100644 (file)
@@ -13,7 +13,7 @@ package sort
 // and then true for the (possibly empty) remainder; Search returns
 // the first true index.  If there is no such index, Search returns n.
 // (Note that the "not found" return value is not -1 as in, for instance,
-// strings.Index).
+// strings.Index.)
 // Search calls f(i) only for i in the range [0, n).
 //
 // A common use of Search is to find the index i for a value x in
index c7c30426aec138ec56f20348d51136d467b1e400..ac8f4a661fc7c345f118239bbf74bf53e5cab8b2 100644 (file)
@@ -72,7 +72,7 @@ func heapSort(data Interface, a, b int) {
        }
 }
 
-// Quicksort, following Bentley and McIlroy,
+// Quicksort, loosely following Bentley and McIlroy,
 // ``Engineering a Sort Function,'' SP&E November 1993.
 
 // medianOfThree moves the median of the three values data[m0], data[m1], data[m2] into data[m1].
@@ -111,59 +111,82 @@ func doPivot(data Interface, lo, hi int) (midlo, midhi int) {
 
        // Invariants are:
        //      data[lo] = pivot (set up by ChoosePivot)
-       //      data[lo <= i < a] = pivot
-       //      data[a <= i < b] < pivot
-       //      data[b <= i < c] is unexamined
-       //      data[c <= i < d] > pivot
-       //      data[d <= i < hi] = pivot
-       //
-       // Once b meets c, can swap the "= pivot" sections
-       // into the middle of the slice.
+       //      data[lo < i < a] < pivot
+       //      data[a <= i < b] <= pivot
+       //      data[b <= i < c] unexamined
+       //      data[c <= i < hi-1] > pivot
+       //      data[hi-1] >= pivot
        pivot := lo
-       a, b, c, d := lo+1, lo+1, hi, hi
+       a, c := lo+1, hi-1
+
+       for ; a != c && data.Less(a, pivot); a++ {
+       }
+       b := a
        for {
-               for b < c {
-                       if data.Less(b, pivot) { // data[b] < pivot
-                               b++
-                       } else if !data.Less(pivot, b) { // data[b] = pivot
-                               data.Swap(a, b)
-                               a++
-                               b++
-                       } else {
-                               break
-                       }
+               for ; b != c && !data.Less(pivot, b); b++ { // data[b] <= pivot
                }
-               for b < c {
-                       if data.Less(pivot, c-1) { // data[c-1] > pivot
-                               c--
-                       } else if !data.Less(c-1, pivot) { // data[c-1] = pivot
-                               data.Swap(c-1, d-1)
-                               c--
-                               d--
-                       } else {
-                               break
-                       }
+               for ; b != c && data.Less(pivot, c-1); c-- { // data[c-1] > pivot
                }
-               if b >= c {
+               if b == c {
                        break
                }
-               // data[b] > pivot; data[c-1] < pivot
+               // data[b] > pivot; data[c-1] <= pivot
                data.Swap(b, c-1)
                b++
                c--
        }
-
-       n := min(b-a, a-lo)
-       swapRange(data, lo, b-n, n)
-
-       n = min(hi-d, d-c)
-       swapRange(data, c, hi-n, n)
-
-       return lo + b - a, hi - (d - c)
+       // If hi-c<3 then there are duplicates (by property of median of nine).
+       // Let be a bit more conservative, and set border to 5.
+       protect := hi-c < 5
+       if !protect && hi-c < (hi-lo)/4 {
+               // Lets test some points for equality to pivot
+               dups := 0
+               if !data.Less(pivot, hi-1) { // data[hi-1] = pivot
+                       data.Swap(c, hi-1)
+                       c++
+                       dups++
+               }
+               if !data.Less(b-1, pivot) { // data[b-1] = pivot
+                       b--
+                       dups++
+               }
+               // m-lo = (hi-lo)/2 > 6
+               // b-lo > (hi-lo)*3/4-1 > 8
+               // ==> m < b ==> data[m] <= pivot
+               if !data.Less(m, pivot) { // data[m] = pivot
+                       data.Swap(m, b-1)
+                       b--
+                       dups++
+               }
+               // if at least 2 points are equal to pivot, assume skewed distribution
+               protect = dups > 1
+       }
+       if protect {
+               // Protect against a lot of duplicates
+               // Add invariant:
+               //      data[a <= i < b] unexamined
+               //      data[b <= i < c] = pivot
+               for {
+                       for ; a != b && !data.Less(b-1, pivot); b-- { // data[b] == pivot
+                       }
+                       for ; a != b && data.Less(a, pivot); a++ { // data[a] < pivot
+                       }
+                       if a == b {
+                               break
+                       }
+                       // data[a] == pivot; data[b-1] < pivot
+                       data.Swap(a, b-1)
+                       a++
+                       b--
+               }
+       }
+       // Swap pivot into middle
+       data.Swap(pivot, b-1)
+       return b - 1, c
 }
 
 func quickSort(data Interface, a, b, maxDepth int) {
-       for b-a > 7 {
+       for b-a > 12 { // Use ShellSort for slices <= 12 elements
                if maxDepth == 0 {
                        heapSort(data, a, b)
                        return
@@ -181,6 +204,13 @@ func quickSort(data Interface, a, b, maxDepth int) {
                }
        }
        if b-a > 1 {
+               // Do ShellSort pass with gap 6
+               // It could be written in this simplified form cause b-a <= 12
+               for i := a + 6; i < b; i++ {
+                       if data.Less(i, i-6) {
+                               data.Swap(i, i-6)
+                       }
+               }
                insertionSort(data, a, b)
        }
 }
index 468c37fafb9bbe2dbe35675275b0c844927e0701..9ff5d1056aa2164171eac806e774629f55f7d697 100644 (file)
@@ -286,25 +286,23 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
        // Now we can figure out the minimum number of digits required.
        // Walk along until d has distinguished itself from upper and lower.
        for i := 0; i < d.nd; i++ {
-               var l, m, u byte // lower, middle, upper digits
+               l := byte('0') // lower digit
                if i < lower.nd {
                        l = lower.d[i]
-               } else {
-                       l = '0'
                }
-               m = d.d[i]
+               m := d.d[i]    // middle digit
+               u := byte('0') // upper digit
                if i < upper.nd {
                        u = upper.d[i]
-               } else {
-                       u = '0'
                }
 
                // Okay to round down (truncate) if lower has a different digit
-               // or if lower is inclusive and is exactly the result of rounding down.
-               okdown := l != m || (inclusive && l == m && i+1 == lower.nd)
+               // or if lower is inclusive and is exactly the result of rounding
+               // down (i.e., and we have reached the final digit of lower).
+               okdown := l != m || inclusive && i+1 == lower.nd
 
-               // Okay to round up if upper has a different digit and
-               // either upper is inclusive or upper is bigger than the result of rounding up.
+               // Okay to round up if upper has a different digit and either upper
+               // is inclusive or upper is bigger than the result of rounding up.
                okup := m != u && (inclusive || m+1 < u || i+1 < upper.nd)
 
                // If it's okay to do either, then round to the nearest one.
index 1b4dcd945b8a35d34f4af3dec2e1b6da3383ff9a..0b9f0feafa675aea7a3609385b92c452c7e0877e 100644 (file)
@@ -18,7 +18,7 @@ type ftoaTest struct {
        s    string
 }
 
-func fdiv(a, b float64) float64 { return a / b } // keep compiler in the dark
+func fdiv(a, b float64) float64 { return a / b }
 
 const (
        below1e23 = 99999999999999974834176
@@ -94,8 +94,8 @@ var ftoatests = []ftoaTest{
        {above1e23, 'f', -1, "100000000000000010000000"},
        {above1e23, 'g', -1, "1.0000000000000001e+23"},
 
-       {fdiv(5e-304, 1e20), 'g', -1, "5e-324"},
-       {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"},
+       {fdiv(5e-304, 1e20), 'g', -1, "5e-324"},   // avoid constant arithmetic
+       {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"}, // avoid constant arithmetic
 
        {32, 'g', -1, "32"},
        {32, 'g', 0, "3e+01"},
index 0cf363c699ed3ea88b6284f8f363e6a8a06c3d15..20a02dec33f2498eb7d38da4588f49765e5bd1b1 100644 (file)
@@ -635,3 +635,23 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
        0xf57a,
        0xf5a4,
 }
+
+// isGraphic lists the graphic runes not matched by IsPrint.
+var isGraphic = []uint16{
+       0x00a0,
+       0x1680,
+       0x2000,
+       0x2001,
+       0x2002,
+       0x2003,
+       0x2004,
+       0x2005,
+       0x2006,
+       0x2007,
+       0x2008,
+       0x2009,
+       0x200a,
+       0x202f,
+       0x205f,
+       0x3000,
+}
index e6f6303356b99e58165b029d6df7ffd2f72141bd..f50d8779408e946a524a1be07cd6a87d81179c82 100644 (file)
@@ -20,7 +20,7 @@ func FormatInt(i int64, base int) string {
        return s
 }
 
-// Itoa is shorthand for FormatInt(i, 10).
+// Itoa is shorthand for FormatInt(int64(i), 10).
 func Itoa(i int) string {
        return FormatInt(int64(i), 10)
 }
index 588d0a00b53b242010cc50afd051065e1ceb5a91..514258060e59693d86cf6c86f314826a1331fb39 100644 (file)
@@ -174,6 +174,23 @@ func main() {
                }
                fmt.Fprintf(&buf, "\t%#04x,\n", r-0x10000)
        }
+       fmt.Fprintf(&buf, "}\n\n")
+
+       // The list of graphic but not "printable" runes is short. Just make one easy table.
+       fmt.Fprintf(&buf, "// isGraphic lists the graphic runes not matched by IsPrint.\n")
+       fmt.Fprintf(&buf, "var isGraphic = []uint16{\n")
+       for r := rune(0); r <= unicode.MaxRune; r++ {
+               if unicode.IsPrint(r) != unicode.IsGraphic(r) {
+                       // Sanity check.
+                       if !unicode.IsGraphic(r) {
+                               log.Fatalf("%U is printable but not graphic\n", r)
+                       }
+                       if r > 0xFFFF { // We expect only 16-bit values.
+                               log.Fatalf("%U too big for isGraphic\n", r)
+                       }
+                       fmt.Fprintf(&buf, "\t%#04x,\n", r)
+               }
+       }
        fmt.Fprintf(&buf, "}\n")
 
        data, err := format.Source(buf.Bytes())
index 53d51b5a46a324a90bbdbf168efba9e3fab75129..40d0667551a63c1c2f28f78f022d75d925cc396b 100644 (file)
@@ -12,7 +12,7 @@ import (
 
 const lowerhex = "0123456789abcdef"
 
-func quoteWith(s string, quote byte, ASCIIonly bool) string {
+func quoteWith(s string, quote byte, ASCIIonly, graphicOnly bool) string {
        var runeTmp [utf8.UTFMax]byte
        buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations.
        buf = append(buf, quote)
@@ -38,7 +38,7 @@ func quoteWith(s string, quote byte, ASCIIonly bool) string {
                                buf = append(buf, byte(r))
                                continue
                        }
-               } else if IsPrint(r) {
+               } else if IsPrint(r) || graphicOnly && isInGraphicList(r) {
                        n := utf8.EncodeRune(runeTmp[:], r)
                        buf = append(buf, runeTmp[:n]...)
                        continue
@@ -90,7 +90,7 @@ func quoteWith(s string, quote byte, ASCIIonly bool) string {
 // control characters and non-printable characters as defined by
 // IsPrint.
 func Quote(s string) string {
-       return quoteWith(s, '"', false)
+       return quoteWith(s, '"', false, false)
 }
 
 // AppendQuote appends a double-quoted Go string literal representing s,
@@ -103,7 +103,7 @@ func AppendQuote(dst []byte, s string) []byte {
 // The returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for
 // non-ASCII characters and non-printable characters as defined by IsPrint.
 func QuoteToASCII(s string) string {
-       return quoteWith(s, '"', true)
+       return quoteWith(s, '"', true, false)
 }
 
 // AppendQuoteToASCII appends a double-quoted Go string literal representing s,
@@ -112,12 +112,25 @@ func AppendQuoteToASCII(dst []byte, s string) []byte {
        return append(dst, QuoteToASCII(s)...)
 }
 
+// QuoteToGraphic returns a double-quoted Go string literal representing s.
+// The returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for
+// non-ASCII characters and non-printable characters as defined by IsGraphic.
+func QuoteToGraphic(s string) string {
+       return quoteWith(s, '"', false, true)
+}
+
+// AppendQuoteToGraphic appends a double-quoted Go string literal representing s,
+// as generated by QuoteToGraphic, to dst and returns the extended buffer.
+func AppendQuoteToGraphic(dst []byte, s string) []byte {
+       return append(dst, QuoteToGraphic(s)...)
+}
+
 // QuoteRune returns a single-quoted Go character literal representing the
-// rune.  The returned string uses Go escape sequences (\t, \n, \xFF, \u0100)
+// rune. The returned string uses Go escape sequences (\t, \n, \xFF, \u0100)
 // for control characters and non-printable characters as defined by IsPrint.
 func QuoteRune(r rune) string {
        // TODO: avoid the allocation here.
-       return quoteWith(string(r), '\'', false)
+       return quoteWith(string(r), '\'', false, false)
 }
 
 // AppendQuoteRune appends a single-quoted Go character literal representing the rune,
@@ -127,12 +140,12 @@ func AppendQuoteRune(dst []byte, r rune) []byte {
 }
 
 // QuoteRuneToASCII returns a single-quoted Go character literal representing
-// the rune.  The returned string uses Go escape sequences (\t, \n, \xFF,
+// the rune. The returned string uses Go escape sequences (\t, \n, \xFF,
 // \u0100) for non-ASCII characters and non-printable characters as defined
 // by IsPrint.
 func QuoteRuneToASCII(r rune) string {
        // TODO: avoid the allocation here.
-       return quoteWith(string(r), '\'', true)
+       return quoteWith(string(r), '\'', true, false)
 }
 
 // AppendQuoteRuneToASCII appends a single-quoted Go character literal representing the rune,
@@ -141,6 +154,21 @@ func AppendQuoteRuneToASCII(dst []byte, r rune) []byte {
        return append(dst, QuoteRuneToASCII(r)...)
 }
 
+// QuoteRuneToGraphic returns a single-quoted Go character literal representing
+// the rune. The returned string uses Go escape sequences (\t, \n, \xFF,
+// \u0100) for non-ASCII characters and non-printable characters as defined
+// by IsGraphic.
+func QuoteRuneToGraphic(r rune) string {
+       // TODO: avoid the allocation here.
+       return quoteWith(string(r), '\'', false, true)
+}
+
+// AppendQuoteRuneToGraphic appends a single-quoted Go character literal representing the rune,
+// as generated by QuoteRuneToGraphic, to dst and returns the extended buffer.
+func AppendQuoteRuneToGraphic(dst []byte, r rune) []byte {
+       return append(dst, QuoteRuneToGraphic(r)...)
+}
+
 // CanBackquote reports whether the string s can be represented
 // unchanged as a single-line backquoted string without control
 // characters other than tab.
@@ -453,3 +481,26 @@ func IsPrint(r rune) bool {
        j := bsearch16(isNotPrint, uint16(r))
        return j >= len(isNotPrint) || isNotPrint[j] != uint16(r)
 }
+
+// IsGraphic reports whether the rune is defined as a Graphic by Unicode. Such
+// characters include letters, marks, numbers, punctuation, symbols, and
+// spaces, from categories L, M, N, P, S, and Zs.
+func IsGraphic(r rune) bool {
+       if IsPrint(r) {
+               return true
+       }
+       return isInGraphicList(r)
+}
+
+// isInGraphicList reports whether the rune is in the isGraphic list. This separation
+// from IsGraphic allows quoteWith to avoid two calls to IsPrint.
+// Should be called only if IsPrint fails.
+func isInGraphicList(r rune) bool {
+       // We know r must fit in 16 bits - see makeisprint.go.
+       if r > 0xFFFF {
+               return false
+       }
+       rr := uint16(r)
+       i := bsearch16(isGraphic, rr)
+       return i < len(isGraphic) && rr == isGraphic[i]
+}
index 3bf162f987e7878e57602d3a34923a0095e6c82c..3e8ec2c98f367828f0572735cdfae09a9e6abdcc 100644 (file)
@@ -10,7 +10,7 @@ import (
        "unicode"
 )
 
-// Verify that our isPrint agrees with unicode.IsPrint
+// Verify that our IsPrint agrees with unicode.IsPrint.
 func TestIsPrint(t *testing.T) {
        n := 0
        for r := rune(0); r <= unicode.MaxRune; r++ {
@@ -24,19 +24,36 @@ func TestIsPrint(t *testing.T) {
        }
 }
 
+// Verify that our IsGraphic agrees with unicode.IsGraphic.
+func TestIsGraphic(t *testing.T) {
+       n := 0
+       for r := rune(0); r <= unicode.MaxRune; r++ {
+               if IsGraphic(r) != unicode.IsGraphic(r) {
+                       t.Errorf("IsGraphic(%U)=%t incorrect", r, IsGraphic(r))
+                       n++
+                       if n > 10 {
+                               return
+                       }
+               }
+       }
+}
+
 type quoteTest struct {
-       in    string
-       out   string
-       ascii string
+       in      string
+       out     string
+       ascii   string
+       graphic string
 }
 
 var quotetests = []quoteTest{
-       {"\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`, `"\a\b\f\r\n\t\v"`},
-       {"\\", `"\\"`, `"\\"`},
-       {"abc\xffdef", `"abc\xffdef"`, `"abc\xffdef"`},
-       {"\u263a", `"☺"`, `"\u263a"`},
-       {"\U0010ffff", `"\U0010ffff"`, `"\U0010ffff"`},
-       {"\x04", `"\x04"`, `"\x04"`},
+       {"\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`, `"\a\b\f\r\n\t\v"`, `"\a\b\f\r\n\t\v"`},
+       {"\\", `"\\"`, `"\\"`, `"\\"`},
+       {"abc\xffdef", `"abc\xffdef"`, `"abc\xffdef"`, `"abc\xffdef"`},
+       {"\u263a", `"☺"`, `"\u263a"`, `"☺"`},
+       {"\U0010ffff", `"\U0010ffff"`, `"\U0010ffff"`, `"\U0010ffff"`},
+       {"\x04", `"\x04"`, `"\x04"`, `"\x04"`},
+       // Some non-printable but graphic runes. Final column is double-quoted.
+       {"!\u00a0!\u2000!\u3000!", `"!\u00a0!\u2000!\u3000!"`, `"!\u00a0!\u2000!\u3000!"`, "\"!\u00a0!\u2000!\u3000!\""},
 }
 
 func TestQuote(t *testing.T) {
@@ -61,22 +78,38 @@ func TestQuoteToASCII(t *testing.T) {
        }
 }
 
+func TestQuoteToGraphic(t *testing.T) {
+       for _, tt := range quotetests {
+               if out := QuoteToGraphic(tt.in); out != tt.graphic {
+                       t.Errorf("QuoteToGraphic(%s) = %s, want %s", tt.in, out, tt.graphic)
+               }
+               if out := AppendQuoteToGraphic([]byte("abc"), tt.in); string(out) != "abc"+tt.graphic {
+                       t.Errorf("AppendQuoteToGraphic(%q, %s) = %s, want %s", "abc", tt.in, out, "abc"+tt.graphic)
+               }
+       }
+}
+
 type quoteRuneTest struct {
-       in    rune
-       out   string
-       ascii string
+       in      rune
+       out     string
+       ascii   string
+       graphic string
 }
 
 var quoterunetests = []quoteRuneTest{
-       {'a', `'a'`, `'a'`},
-       {'\a', `'\a'`, `'\a'`},
-       {'\\', `'\\'`, `'\\'`},
-       {0xFF, `'ÿ'`, `'\u00ff'`},
-       {0x263a, `'☺'`, `'\u263a'`},
-       {0xfffd, `'�'`, `'\ufffd'`},
-       {0x0010ffff, `'\U0010ffff'`, `'\U0010ffff'`},
-       {0x0010ffff + 1, `'�'`, `'\ufffd'`},
-       {0x04, `'\x04'`, `'\x04'`},
+       {'a', `'a'`, `'a'`, `'a'`},
+       {'\a', `'\a'`, `'\a'`, `'\a'`},
+       {'\\', `'\\'`, `'\\'`, `'\\'`},
+       {0xFF, `'ÿ'`, `'\u00ff'`, `'ÿ'`},
+       {0x263a, `'☺'`, `'\u263a'`, `'☺'`},
+       {0xfffd, `'�'`, `'\ufffd'`, `'�'`},
+       {0x0010ffff, `'\U0010ffff'`, `'\U0010ffff'`, `'\U0010ffff'`},
+       {0x0010ffff + 1, `'�'`, `'\ufffd'`, `'�'`},
+       {0x04, `'\x04'`, `'\x04'`, `'\x04'`},
+       // Some differences between graphic and printable. Note the last column is double-quoted.
+       {'\u00a0', `'\u00a0'`, `'\u00a0'`, "'\u00a0'"},
+       {'\u2000', `'\u2000'`, `'\u2000'`, "'\u2000'"},
+       {'\u3000', `'\u3000'`, `'\u3000'`, "'\u3000'"},
 }
 
 func TestQuoteRune(t *testing.T) {
@@ -101,6 +134,17 @@ func TestQuoteRuneToASCII(t *testing.T) {
        }
 }
 
+func TestQuoteRuneToGraphic(t *testing.T) {
+       for _, tt := range quoterunetests {
+               if out := QuoteRuneToGraphic(tt.in); out != tt.graphic {
+                       t.Errorf("QuoteRuneToGraphic(%U) = %s, want %s", tt.in, out, tt.graphic)
+               }
+               if out := AppendQuoteRuneToGraphic([]byte("abc"), tt.in); string(out) != "abc"+tt.graphic {
+                       t.Errorf("AppendQuoteRuneToGraphic(%q, %U) = %s, want %s", "abc", tt.in, out, "abc"+tt.graphic)
+               }
+       }
+}
+
 type canBackquoteTest struct {
        in  string
        out bool
index 7243e16b127086e4931962c0536a45fba8d01792..3f9d63b5a4a3e7ba3a33e6e879bf19116a5e14e1 100644 (file)
@@ -60,6 +60,28 @@ func ExampleEqualFold() {
        // Output: true
 }
 
+func ExampleHasPrefix() {
+       fmt.Println(strings.HasPrefix("Gopher", "Go"))
+       fmt.Println(strings.HasPrefix("Gopher", "C"))
+       fmt.Println(strings.HasPrefix("Gopher", ""))
+       // Output:
+       // true
+       // false
+       // true
+}
+
+func ExampleHasSuffix() {
+       fmt.Println(strings.HasSuffix("Amigo", "go"))
+       fmt.Println(strings.HasSuffix("Amigo", "O"))
+       fmt.Println(strings.HasSuffix("Amigo", "Ami"))
+       fmt.Println(strings.HasSuffix("Amigo", ""))
+       // Output:
+       // true
+       // false
+       // false
+       // true
+}
+
 func ExampleIndex() {
        fmt.Println(strings.Index("chicken", "ken"))
        fmt.Println(strings.Index("chicken", "dmr"))
index dd51dabb3225b0d5a1aa1ff3529e8edf8703c112..37d5647ffd620a16bb82d869572f4c8168f3184e 100644 (file)
@@ -143,43 +143,6 @@ func ContainsRune(s string, r rune) bool {
        return IndexRune(s, r) >= 0
 }
 
-// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
-func Index(s, sep string) int {
-       n := len(sep)
-       switch {
-       case n == 0:
-               return 0
-       case n == 1:
-               return IndexByte(s, sep[0])
-       case n == len(s):
-               if sep == s {
-                       return 0
-               }
-               return -1
-       case n > len(s):
-               return -1
-       }
-       // Rabin-Karp search
-       hashsep, pow := hashStr(sep)
-       var h uint32
-       for i := 0; i < n; i++ {
-               h = h*primeRK + uint32(s[i])
-       }
-       if h == hashsep && s[:n] == sep {
-               return 0
-       }
-       for i := n; i < len(s); {
-               h *= primeRK
-               h += uint32(s[i])
-               h -= pow * uint32(s[i-n])
-               i++
-               if h == hashsep && s[i-n:i] == sep {
-                       return i - n
-               }
-       }
-       return -1
-}
-
 // LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s.
 func LastIndex(s, sep string) int {
        n := len(sep)
diff --git a/libgo/go/strings/strings_amd64.go b/libgo/go/strings/strings_amd64.go
new file mode 100644 (file)
index 0000000..376113f
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2015 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 strings
+
+// indexShortStr returns the index of the first instance of c in s, or -1 if c is not present in s.
+// indexShortStr requires 2 <= len(c) <= shortStringLen
+func indexShortStr(s, c string) int // ../runtime/asm_$GOARCH.s
+const shortStringLen = 31
+
+// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
+func Index(s, sep string) int {
+       n := len(sep)
+       switch {
+       case n == 0:
+               return 0
+       case n == 1:
+               return IndexByte(s, sep[0])
+       case n <= shortStringLen:
+               return indexShortStr(s, sep)
+       case n == len(s):
+               if sep == s {
+                       return 0
+               }
+               return -1
+       case n > len(s):
+               return -1
+       }
+       // Rabin-Karp search
+       hashsep, pow := hashStr(sep)
+       var h uint32
+       for i := 0; i < n; i++ {
+               h = h*primeRK + uint32(s[i])
+       }
+       if h == hashsep && s[:n] == sep {
+               return 0
+       }
+       for i := n; i < len(s); {
+               h *= primeRK
+               h += uint32(s[i])
+               h -= pow * uint32(s[i-n])
+               i++
+               if h == hashsep && s[i-n:i] == sep {
+                       return i - n
+               }
+       }
+       return -1
+}
diff --git a/libgo/go/strings/strings_generic.go b/libgo/go/strings/strings_generic.go
new file mode 100644 (file)
index 0000000..811cb80
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2015 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 !amd64
+
+package strings
+
+// TODO: implements short string optimization on non amd64 platforms
+// and get rid of strings_amd64.go
+
+// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
+func Index(s, sep string) int {
+       n := len(sep)
+       switch {
+       case n == 0:
+               return 0
+       case n == 1:
+               return IndexByte(s, sep[0])
+       case n == len(s):
+               if sep == s {
+                       return 0
+               }
+               return -1
+       case n > len(s):
+               return -1
+       }
+       // Rabin-Karp search
+       hashsep, pow := hashStr(sep)
+       var h uint32
+       for i := 0; i < n; i++ {
+               h = h*primeRK + uint32(s[i])
+       }
+       if h == hashsep && s[:n] == sep {
+               return 0
+       }
+       for i := n; i < len(s); {
+               h *= primeRK
+               h += uint32(s[i])
+               h -= pow * uint32(s[i-n])
+               i++
+               if h == hashsep && s[i-n:i] == sep {
+                       return i - n
+               }
+       }
+       return -1
+}
index 4e21deaecde12078605f72f02fee3b0517df6989..49f55fe38c764d9c7e2cd43884b515298ccb326f 100644 (file)
@@ -59,6 +59,59 @@ var indexTests = []IndexTest{
        {"abc", "b", 1},
        {"abc", "c", 2},
        {"abc", "x", -1},
+       // test special cases in Index() for short strings
+       {"", "ab", -1},
+       {"bc", "ab", -1},
+       {"ab", "ab", 0},
+       {"xab", "ab", 1},
+       {"xab"[:2], "ab", -1},
+       {"", "abc", -1},
+       {"xbc", "abc", -1},
+       {"abc", "abc", 0},
+       {"xabc", "abc", 1},
+       {"xabc"[:3], "abc", -1},
+       {"xabxc", "abc", -1},
+       {"", "abcd", -1},
+       {"xbcd", "abcd", -1},
+       {"abcd", "abcd", 0},
+       {"xabcd", "abcd", 1},
+       {"xyabcd"[:5], "abcd", -1},
+       {"xbcqq", "abcqq", -1},
+       {"abcqq", "abcqq", 0},
+       {"xabcqq", "abcqq", 1},
+       {"xyabcqq"[:6], "abcqq", -1},
+       {"xabxcqq", "abcqq", -1},
+       {"xabcqxq", "abcqq", -1},
+       {"", "01234567", -1},
+       {"32145678", "01234567", -1},
+       {"01234567", "01234567", 0},
+       {"x01234567", "01234567", 1},
+       {"xx01234567"[:9], "01234567", -1},
+       {"", "0123456789", -1},
+       {"3214567844", "0123456789", -1},
+       {"0123456789", "0123456789", 0},
+       {"x0123456789", "0123456789", 1},
+       {"xyz0123456789"[:12], "0123456789", -1},
+       {"x01234567x89", "0123456789", -1},
+       {"", "0123456789012345", -1},
+       {"3214567889012345", "0123456789012345", -1},
+       {"0123456789012345", "0123456789012345", 0},
+       {"x0123456789012345", "0123456789012345", 1},
+       {"", "01234567890123456789", -1},
+       {"32145678890123456789", "01234567890123456789", -1},
+       {"01234567890123456789", "01234567890123456789", 0},
+       {"x01234567890123456789", "01234567890123456789", 1},
+       {"xyz01234567890123456789"[:22], "01234567890123456789", -1},
+       {"", "0123456789012345678901234567890", -1},
+       {"321456788901234567890123456789012345678911", "0123456789012345678901234567890", -1},
+       {"0123456789012345678901234567890", "0123456789012345678901234567890", 0},
+       {"x0123456789012345678901234567890", "0123456789012345678901234567890", 1},
+       {"xyz0123456789012345678901234567890"[:33], "0123456789012345678901234567890", -1},
+       {"", "01234567890123456789012345678901", -1},
+       {"32145678890123456789012345678901234567890211", "01234567890123456789012345678901", -1},
+       {"01234567890123456789012345678901", "01234567890123456789012345678901", 0},
+       {"x01234567890123456789012345678901", "01234567890123456789012345678901", 1},
+       {"xyz01234567890123456789012345678901"[:34], "01234567890123456789012345678901", -1},
 }
 
 var lastIndexTests = []IndexTest{
index 9e6bc170f19b853a66111c418037678e9e7ed650..0aefcda9084f3ed4f1da11654c01ca080ecfd0f5 100644 (file)
@@ -5,6 +5,7 @@
 package sync
 
 import (
+       "internal/race"
        "sync/atomic"
        "unsafe"
 )
@@ -51,12 +52,12 @@ func NewCond(l Locker) *Cond {
 //
 func (c *Cond) Wait() {
        c.checker.check()
-       if raceenabled {
-               raceDisable()
+       if race.Enabled {
+               race.Disable()
        }
        atomic.AddUint32(&c.waiters, 1)
-       if raceenabled {
-               raceEnable()
+       if race.Enabled {
+               race.Enable()
        }
        c.L.Unlock()
        runtime_Syncsemacquire(&c.sema)
@@ -81,14 +82,14 @@ func (c *Cond) Broadcast() {
 
 func (c *Cond) signalImpl(all bool) {
        c.checker.check()
-       if raceenabled {
-               raceDisable()
+       if race.Enabled {
+               race.Disable()
        }
        for {
                old := atomic.LoadUint32(&c.waiters)
                if old == 0 {
-                       if raceenabled {
-                               raceEnable()
+                       if race.Enabled {
+                               race.Enable()
                        }
                        return
                }
@@ -97,8 +98,8 @@ func (c *Cond) signalImpl(all bool) {
                        new = 0
                }
                if atomic.CompareAndSwapUint32(&c.waiters, old, new) {
-                       if raceenabled {
-                               raceEnable()
+                       if race.Enabled {
+                               race.Enable()
                        }
                        runtime_Syncsemrelease(&c.sema, old-new)
                        return
index 6f49b3bd8a8f790536fdc5659113cec7c43f14b3..fa5983a2d1e5d23ccf3abb0091a036b1badf5dbb 100644 (file)
@@ -7,5 +7,3 @@ package sync
 // Export for testing.
 var Runtime_Semacquire = runtime_Semacquire
 var Runtime_Semrelease = runtime_Semrelease
-
-const RaceEnabled = raceenabled
index 3f280ad719d577c72d5df97cdb1cc7485e305be0..eb526144c52a4999572b3013a301215e250af794 100644 (file)
@@ -11,6 +11,7 @@
 package sync
 
 import (
+       "internal/race"
        "sync/atomic"
        "unsafe"
 )
@@ -41,8 +42,8 @@ const (
 func (m *Mutex) Lock() {
        // Fast path: grab unlocked mutex.
        if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
-               if raceenabled {
-                       raceAcquire(unsafe.Pointer(m))
+               if race.Enabled {
+                       race.Acquire(unsafe.Pointer(m))
                }
                return
        }
@@ -85,8 +86,8 @@ func (m *Mutex) Lock() {
                }
        }
 
-       if raceenabled {
-               raceAcquire(unsafe.Pointer(m))
+       if race.Enabled {
+               race.Acquire(unsafe.Pointer(m))
        }
 }
 
@@ -97,9 +98,9 @@ func (m *Mutex) Lock() {
 // It is allowed for one goroutine to lock a Mutex and then
 // arrange for another goroutine to unlock it.
 func (m *Mutex) Unlock() {
-       if raceenabled {
+       if race.Enabled {
                _ = m.state
-               raceRelease(unsafe.Pointer(m))
+               race.Release(unsafe.Pointer(m))
        }
 
        // Fast path: drop lock bit.
index 0cf0637024402a9fb0f5a9bf99b28463286f5dd9..381af0bead5034c3b2a2325c48b6683c2bc2731e 100644 (file)
@@ -5,6 +5,7 @@
 package sync
 
 import (
+       "internal/race"
        "runtime"
        "sync/atomic"
        "unsafe"
@@ -59,7 +60,7 @@ type poolLocal struct {
 
 // Put adds x to the pool.
 func (p *Pool) Put(x interface{}) {
-       if raceenabled {
+       if race.Enabled {
                // Under race detector the Pool degenerates into no-op.
                // It's conforming, simple and does not introduce excessive
                // happens-before edges between unrelated goroutines.
@@ -91,7 +92,7 @@ func (p *Pool) Put(x interface{}) {
 // If Get would otherwise return nil and p.New is non-nil, Get returns
 // the result of calling p.New.
 func (p *Pool) Get() interface{} {
-       if raceenabled {
+       if race.Enabled {
                if p.New != nil {
                        return p.New()
                }
diff --git a/libgo/go/sync/race.go b/libgo/go/sync/race.go
deleted file mode 100644 (file)
index fd0277d..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2012 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 sync
-
-import (
-       "runtime"
-       "unsafe"
-)
-
-const raceenabled = true
-
-func raceAcquire(addr unsafe.Pointer) {
-       runtime.RaceAcquire(addr)
-}
-
-func raceRelease(addr unsafe.Pointer) {
-       runtime.RaceRelease(addr)
-}
-
-func raceReleaseMerge(addr unsafe.Pointer) {
-       runtime.RaceReleaseMerge(addr)
-}
-
-func raceDisable() {
-       runtime.RaceDisable()
-}
-
-func raceEnable() {
-       runtime.RaceEnable()
-}
-
-func raceRead(addr unsafe.Pointer) {
-       runtime.RaceRead(addr)
-}
-
-func raceWrite(addr unsafe.Pointer) {
-       runtime.RaceWrite(addr)
-}
diff --git a/libgo/go/sync/race0.go b/libgo/go/sync/race0.go
deleted file mode 100644 (file)
index 65ada1c..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2012 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 sync
-
-import (
-       "unsafe"
-)
-
-const raceenabled = false
-
-func raceAcquire(addr unsafe.Pointer) {
-}
-
-func raceRelease(addr unsafe.Pointer) {
-}
-
-func raceReleaseMerge(addr unsafe.Pointer) {
-}
-
-func raceDisable() {
-}
-
-func raceEnable() {
-}
-
-func raceRead(addr unsafe.Pointer) {
-}
-
-func raceWrite(addr unsafe.Pointer) {
-}
index 0e8a58e5f03ad3830b3efe43cb145b1e3df3a202..d438c93c88e074428d981e013ca6366a9d819f9c 100644 (file)
@@ -5,6 +5,7 @@
 package sync
 
 import (
+       "internal/race"
        "sync/atomic"
        "unsafe"
 )
@@ -27,17 +28,17 @@ const rwmutexMaxReaders = 1 << 30
 
 // RLock locks rw for reading.
 func (rw *RWMutex) RLock() {
-       if raceenabled {
+       if race.Enabled {
                _ = rw.w.state
-               raceDisable()
+               race.Disable()
        }
        if atomic.AddInt32(&rw.readerCount, 1) < 0 {
                // A writer is pending, wait for it.
                runtime_Semacquire(&rw.readerSem)
        }
-       if raceenabled {
-               raceEnable()
-               raceAcquire(unsafe.Pointer(&rw.readerSem))
+       if race.Enabled {
+               race.Enable()
+               race.Acquire(unsafe.Pointer(&rw.readerSem))
        }
 }
 
@@ -46,14 +47,14 @@ func (rw *RWMutex) RLock() {
 // It is a run-time error if rw is not locked for reading
 // on entry to RUnlock.
 func (rw *RWMutex) RUnlock() {
-       if raceenabled {
+       if race.Enabled {
                _ = rw.w.state
-               raceReleaseMerge(unsafe.Pointer(&rw.writerSem))
-               raceDisable()
+               race.ReleaseMerge(unsafe.Pointer(&rw.writerSem))
+               race.Disable()
        }
        if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {
                if r+1 == 0 || r+1 == -rwmutexMaxReaders {
-                       raceEnable()
+                       race.Enable()
                        panic("sync: RUnlock of unlocked RWMutex")
                }
                // A writer is pending.
@@ -62,8 +63,8 @@ func (rw *RWMutex) RUnlock() {
                        runtime_Semrelease(&rw.writerSem)
                }
        }
-       if raceenabled {
-               raceEnable()
+       if race.Enabled {
+               race.Enable()
        }
 }
 
@@ -74,9 +75,9 @@ func (rw *RWMutex) RUnlock() {
 // a blocked Lock call excludes new readers from acquiring
 // the lock.
 func (rw *RWMutex) Lock() {
-       if raceenabled {
+       if race.Enabled {
                _ = rw.w.state
-               raceDisable()
+               race.Disable()
        }
        // First, resolve competition with other writers.
        rw.w.Lock()
@@ -86,10 +87,10 @@ func (rw *RWMutex) Lock() {
        if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
                runtime_Semacquire(&rw.writerSem)
        }
-       if raceenabled {
-               raceEnable()
-               raceAcquire(unsafe.Pointer(&rw.readerSem))
-               raceAcquire(unsafe.Pointer(&rw.writerSem))
+       if race.Enabled {
+               race.Enable()
+               race.Acquire(unsafe.Pointer(&rw.readerSem))
+               race.Acquire(unsafe.Pointer(&rw.writerSem))
        }
 }
 
@@ -100,17 +101,17 @@ func (rw *RWMutex) Lock() {
 // goroutine.  One goroutine may RLock (Lock) an RWMutex and then
 // arrange for another goroutine to RUnlock (Unlock) it.
 func (rw *RWMutex) Unlock() {
-       if raceenabled {
+       if race.Enabled {
                _ = rw.w.state
-               raceRelease(unsafe.Pointer(&rw.readerSem))
-               raceRelease(unsafe.Pointer(&rw.writerSem))
-               raceDisable()
+               race.Release(unsafe.Pointer(&rw.readerSem))
+               race.Release(unsafe.Pointer(&rw.writerSem))
+               race.Disable()
        }
 
        // Announce to readers there is no active writer.
        r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
        if r >= rwmutexMaxReaders {
-               raceEnable()
+               race.Enable()
                panic("sync: Unlock of unlocked RWMutex")
        }
        // Unblock blocked readers, if any.
@@ -119,8 +120,8 @@ func (rw *RWMutex) Unlock() {
        }
        // Allow other writers to proceed.
        rw.w.Unlock()
-       if raceenabled {
-               raceEnable()
+       if race.Enabled {
+               race.Enable()
        }
 }
 
index de399e64ebbfc83974d00b7fbc09f2333a51f29a..c77fec306c06937dca7f3ec7428b7c4dfee1b896 100644 (file)
@@ -5,6 +5,7 @@
 package sync
 
 import (
+       "internal/race"
        "sync/atomic"
        "unsafe"
 )
@@ -46,24 +47,24 @@ func (wg *WaitGroup) state() *uint64 {
 // See the WaitGroup example.
 func (wg *WaitGroup) Add(delta int) {
        statep := wg.state()
-       if raceenabled {
+       if race.Enabled {
                _ = *statep // trigger nil deref early
                if delta < 0 {
                        // Synchronize decrements with Wait.
-                       raceReleaseMerge(unsafe.Pointer(wg))
+                       race.ReleaseMerge(unsafe.Pointer(wg))
                }
-               raceDisable()
-               defer raceEnable()
+               race.Disable()
+               defer race.Enable()
        }
        state := atomic.AddUint64(statep, uint64(delta)<<32)
        v := int32(state >> 32)
        w := uint32(state)
-       if raceenabled {
+       if race.Enabled {
                if delta > 0 && v == int32(delta) {
                        // The first increment must be synchronized with Wait.
                        // Need to model this as a read, because there can be
                        // several concurrent wg.counter transitions from 0.
-                       raceRead(unsafe.Pointer(&wg.sema))
+                       race.Read(unsafe.Pointer(&wg.sema))
                }
        }
        if v < 0 {
@@ -98,9 +99,9 @@ func (wg *WaitGroup) Done() {
 // Wait blocks until the WaitGroup counter is zero.
 func (wg *WaitGroup) Wait() {
        statep := wg.state()
-       if raceenabled {
+       if race.Enabled {
                _ = *statep // trigger nil deref early
-               raceDisable()
+               race.Disable()
        }
        for {
                state := atomic.LoadUint64(statep)
@@ -108,28 +109,28 @@ func (wg *WaitGroup) Wait() {
                w := uint32(state)
                if v == 0 {
                        // Counter is 0, no need to wait.
-                       if raceenabled {
-                               raceEnable()
-                               raceAcquire(unsafe.Pointer(wg))
+                       if race.Enabled {
+                               race.Enable()
+                               race.Acquire(unsafe.Pointer(wg))
                        }
                        return
                }
                // Increment waiters count.
                if atomic.CompareAndSwapUint64(statep, state, state+1) {
-                       if raceenabled && w == 0 {
+                       if race.Enabled && w == 0 {
                                // Wait must be synchronized with the first Add.
                                // Need to model this is as a write to race with the read in Add.
                                // As a consequence, can do the write only for the first waiter,
                                // otherwise concurrent Waits will race with each other.
-                               raceWrite(unsafe.Pointer(&wg.sema))
+                               race.Write(unsafe.Pointer(&wg.sema))
                        }
                        runtime_Semacquire(&wg.sema)
                        if *statep != 0 {
                                panic("sync: WaitGroup is reused before previous Wait has returned")
                        }
-                       if raceenabled {
-                               raceEnable()
-                               raceAcquire(unsafe.Pointer(wg))
+                       if race.Enabled {
+                               race.Enable()
+                               race.Acquire(unsafe.Pointer(wg))
                        }
                        return
                }
index 3e3e3bf824396cfde3310a0fb3fcea1532cdae78..a5816609408d9b3a2aa654a9a356844c8ec31a6e 100644 (file)
@@ -5,6 +5,7 @@
 package sync_test
 
 import (
+       "internal/race"
        "runtime"
        . "sync"
        "sync/atomic"
@@ -48,7 +49,7 @@ func TestWaitGroup(t *testing.T) {
 }
 
 func knownRacy(t *testing.T) {
-       if RaceEnabled {
+       if race.Enabled {
                t.Skip("skipping known-racy test under the race detector")
        }
 }
index ede3d6a329e49997d608d57d57a611bd046c531c..d7634c995ed85f9bf5ae15414d98f5f708d48ab5 100644 (file)
@@ -46,3 +46,13 @@ var (
        EACCES       = NewError("access permission denied")
        EAFNOSUPPORT = NewError("address family not supported by protocol")
 )
+
+// Notes
+const (
+       SIGABRT = Note("abort")
+       SIGALRM = Note("alarm")
+       SIGHUP  = Note("hangup")
+       SIGINT  = Note("interrupt")
+       SIGKILL = Note("kill")
+       SIGTERM = Note("interrupt")
+)
index 9042ce263aae487b19114faba4be498be9794dc8..75126730f59b8d1c9a3c155c47b9bf9bccaf09dd 100644 (file)
@@ -36,6 +36,7 @@ func runtime_AfterFork()
 // For the same reason compiler does not race instrument it.
 // The calls to RawSyscall are okay because they are assembly
 // functions that do not grow the stack.
+//go:norace
 func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
        // Declare all variables at top in case any
        // declarations require heap allocation (e.g., err1).
index 540efb3a6d8615e39e962c706f11f816fa3f8bcf..6987bc1f4ecc6721e1a0c47c10c7b6e21d7f6574 100644 (file)
@@ -57,6 +57,7 @@ func runtime_AfterFork()
 // For the same reason compiler does not race instrument it.
 // The calls to RawSyscall are okay because they are assembly
 // functions that do not grow the stack.
+//go:norace
 func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
        // Declare all variables at top in case any
        // declarations require heap allocation (e.g., err1).
@@ -201,11 +202,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
                                goto childerror
                        }
                }
-               err1 = raw_setgid(int(cred.Gid))
+               _, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0)
                if err1 != 0 {
                        goto childerror
                }
-               err1 = raw_setuid(int(cred.Uid))
+               _, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0)
                if err1 != 0 {
                        goto childerror
                }
index 60d2734f66a8b0485bd8e77c4cabec10e546826f..6d319411840f5efd5076d33da87c562e6d92d5aa 100644 (file)
@@ -10,13 +10,22 @@ import (
        "io/ioutil"
        "os"
        "os/exec"
-       "regexp"
-       "strconv"
        "strings"
        "syscall"
        "testing"
 )
 
+// Check if we are in a chroot by checking if the inode of / is
+// different from 2 (there is no better test available to non-root on
+// linux).
+func isChrooted(t *testing.T) bool {
+       root, err := os.Stat("/")
+       if err != nil {
+               t.Fatalf("cannot stat /: %v", err)
+       }
+       return root.Sys().(*syscall.Stat_t).Ino != 2
+}
+
 func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd {
        if _, err := os.Stat("/proc/self/ns/user"); err != nil {
                if os.IsNotExist(err) {
@@ -24,6 +33,26 @@ func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd {
                }
                t.Fatalf("Failed to stat /proc/self/ns/user: %v", err)
        }
+       if isChrooted(t) {
+               // create_user_ns in the kernel (see
+               // https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/kernel/user_namespace.c)
+               // forbids the creation of user namespaces when chrooted.
+               t.Skip("cannot create user namespaces when chrooted")
+       }
+       // On some systems, there is a sysctl setting.
+       if os.Getuid() != 0 {
+               data, errRead := ioutil.ReadFile("/proc/sys/kernel/unprivileged_userns_clone")
+               if errRead == nil && data[0] == '0' {
+                       t.Skip("kernel prohibits user namespace in unprivileged process")
+               }
+       }
+       // When running under the Go continuous build, skip tests for
+       // now when under Kubernetes. (where things are root but not quite)
+       // Both of these are our own environment variables.
+       // See Issue 12815.
+       if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" {
+               t.Skip("skipping test on Kubernetes-based builders; see Issue 12815")
+       }
        cmd := exec.Command("whoami")
        cmd.SysProcAttr = &syscall.SysProcAttr{
                Cloneflags: syscall.CLONE_NEWUSER,
@@ -42,14 +71,6 @@ func testNEWUSERRemap(t *testing.T, uid, gid int, setgroups bool) {
        cmd := whoamiCmd(t, uid, gid, setgroups)
        out, err := cmd.CombinedOutput()
        if err != nil {
-               // On some systems, there is a sysctl setting.
-               if os.IsPermission(err) && os.Getuid() != 0 {
-                       data, errRead := ioutil.ReadFile("/proc/sys/kernel/unprivileged_userns_clone")
-                       if errRead == nil && data[0] == '0' {
-                               t.Skip("kernel prohibits user namespace in unprivileged process")
-                       }
-               }
-
                t.Fatalf("Cmd failed with err %v, output: %s", err, out)
        }
        sout := strings.TrimSpace(string(out))
@@ -73,22 +94,6 @@ func TestCloneNEWUSERAndRemapRootEnableSetgroups(t *testing.T) {
        testNEWUSERRemap(t, 0, 0, false)
 }
 
-// kernelVersion returns the major and minor versions of the Linux
-// kernel version.  It calls t.Skip if it can't figure it out.
-func kernelVersion(t *testing.T) (int, int) {
-       bytes, err := ioutil.ReadFile("/proc/version")
-       if err != nil {
-               t.Skipf("can't get kernel version: %v", err)
-       }
-       matches := regexp.MustCompile("([0-9]+).([0-9]+)").FindSubmatch(bytes)
-       if len(matches) < 3 {
-               t.Skipf("can't get kernel version from %s", bytes)
-       }
-       major, _ := strconv.Atoi(string(matches[1]))
-       minor, _ := strconv.Atoi(string(matches[2]))
-       return major, minor
-}
-
 func TestCloneNEWUSERAndRemapNoRootDisableSetgroups(t *testing.T) {
        if os.Getuid() == 0 {
                t.Skip("skipping unprivileged user only test")
@@ -109,3 +114,11 @@ func TestCloneNEWUSERAndRemapNoRootSetgroupsEnableSetgroups(t *testing.T) {
                t.Fatalf("Unprivileged gid_map rewriting with GidMappingsEnableSetgroups must fail")
        }
 }
+
+func TestEmptyCredGroupsDisableSetgroups(t *testing.T) {
+       cmd := whoamiCmd(t, os.Getuid(), os.Getgid(), false)
+       cmd.SysProcAttr.Credential = &syscall.Credential{}
+       if err := cmd.Run(); err != nil {
+               t.Fatal(err)
+       }
+}
index d1927de9b4b6d19c009fb55895b146170f01b25a..3b772e6ddb5f3bb0d36b148c999408e66147f9a8 100644 (file)
@@ -65,12 +65,6 @@ import (
 //sysnb raw_setgroups(size int, list unsafe.Pointer) (err Errno)
 //setgroups(size Size_t, list *Gid_t) _C_int
 
-//sysnb raw_setuid(uid int) (err Errno)
-//setuid(uid Uid_t) _C_int
-
-//sysnb raw_setgid(gid int) (err Errno)
-//setgid(gid Gid_t) _C_int
-
 // Lock synchronizing creation of new file descriptors with fork.
 //
 // We want the child in a fork/exec sequence to inherit only the
index f77260854c731acb9a30bc4ea6470f5dfd1140bc..fe6a3e3a27bf9a847450e1907128bb1254c6a8c2 100644 (file)
@@ -6,13 +6,16 @@
 
 package syscall
 
-import "unsafe"
+import (
+       "internal/race"
+       "unsafe"
+)
 
 //sys  sendfile(outfd int, infd int, offset *Offset_t, count int) (written int, err error)
 //sendfile(outfd _C_int, infd _C_int, offset *Offset_t, count Size_t) Ssize_t
 func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
-       if raceenabled {
-               raceReleaseMerge(unsafe.Pointer(&ioSync))
+       if race.Enabled {
+               race.ReleaseMerge(unsafe.Pointer(&ioSync))
        }
        var soff Offset_t
        var psoff *Offset_t
index f0479eb02eeec9df86c9a85d9d761da7133f2ddc..ff81f547102c8a01439689c86571d4067ac733ee 100644 (file)
@@ -6,7 +6,10 @@
 
 package syscall
 
-import "unsafe"
+import (
+       "internal/race"
+       "unsafe"
+)
 
 //sys  Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 //__go_openat(dirfd _C_int, path *byte, flags _C_int, mode Mode_t) _C_int
@@ -321,8 +324,8 @@ func Pipe2(p []int, flags int) (err error) {
 //sys  sendfile(outfd int, infd int, offset *Offset_t, count int) (written int, err error)
 //sendfile64(outfd _C_int, infd _C_int, offset *Offset_t, count Size_t) Ssize_t
 func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
-       if raceenabled {
-               raceReleaseMerge(unsafe.Pointer(&ioSync))
+       if race.Enabled {
+               race.ReleaseMerge(unsafe.Pointer(&ioSync))
        }
        var soff Offset_t
        var psoff *Offset_t
diff --git a/libgo/go/syscall/msan.go b/libgo/go/syscall/msan.go
new file mode 100644 (file)
index 0000000..edd8d1e
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2015 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 msan
+
+package syscall
+
+import (
+       "runtime"
+       "unsafe"
+)
+
+const msanenabled = true
+
+func msanRead(addr unsafe.Pointer, len int) {
+       runtime.MSanRead(addr, len)
+}
+
+func msanWrite(addr unsafe.Pointer, len int) {
+       runtime.MSanWrite(addr, len)
+}
diff --git a/libgo/go/syscall/msan0.go b/libgo/go/syscall/msan0.go
new file mode 100644 (file)
index 0000000..7617494
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2015 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 !msan
+
+package syscall
+
+import (
+       "unsafe"
+)
+
+const msanenabled = false
+
+func msanRead(addr unsafe.Pointer, len int) {
+}
+
+func msanWrite(addr unsafe.Pointer, len int) {
+}
diff --git a/libgo/go/syscall/race0.go b/libgo/go/syscall/race0.go
deleted file mode 100644 (file)
index b02f882..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2012 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 syscall
-
-import (
-       "unsafe"
-)
-
-const raceenabled = false
-
-func raceAcquire(addr unsafe.Pointer) {
-}
-
-func raceReleaseMerge(addr unsafe.Pointer) {
-}
-
-func raceReadRange(addr unsafe.Pointer, len int) {
-}
-
-func raceWriteRange(addr unsafe.Pointer, len int) {
-}
index c62fdc3c81dd5cc67f8d0be75c5c9c2f212a6ca6..c635a1385e2b20904ebfee9b6b55f87300103ef9 100644 (file)
@@ -44,6 +44,9 @@ func rsaAlignOf(salen int) int {
 
 // parseSockaddrLink parses b as a datalink socket address.
 func parseSockaddrLink(b []byte) (*SockaddrDatalink, error) {
+       if len(b) < 8 {
+               return nil, EINVAL
+       }
        sa, _, err := parseLinkLayerAddr(b[4:])
        if err != nil {
                return nil, err
@@ -77,16 +80,16 @@ func parseLinkLayerAddr(b []byte) (*SockaddrDatalink, int, error) {
                Slen byte
        }
        lla := (*linkLayerAddr)(unsafe.Pointer(&b[0]))
-       l := rsaAlignOf(int(4 + lla.Nlen + lla.Alen + lla.Slen))
+       l := 4 + int(lla.Nlen) + int(lla.Alen) + int(lla.Slen)
        if len(b) < l {
                return nil, 0, EINVAL
        }
        b = b[4:]
        sa := &SockaddrDatalink{Type: lla.Type, Nlen: lla.Nlen, Alen: lla.Alen, Slen: lla.Slen}
-       for i := 0; len(sa.Data) > i && i < int(lla.Nlen+lla.Alen+lla.Slen); i++ {
+       for i := 0; len(sa.Data) > i && i < l-4; i++ {
                sa.Data[i] = int8(b[i])
        }
-       return sa, l, nil
+       return sa, rsaAlignOf(l), nil
 }
 
 // parseSockaddrInet parses b as an internet socket address.
@@ -336,7 +339,7 @@ func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) {
        return msgs, nil
 }
 
-// ParseRoutingMessage parses msg's payload as raw sockaddrs and
+// ParseRoutingSockaddr parses msg's payload as raw sockaddrs and
 // returns the slice containing the Sockaddr interfaces.
 func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) {
        sas, err := msg.sockaddr()
index 8617663d43a4fdce03fead5d14d06907013ae8ae..74d11f9f0a578e405c3077aad84b6a9e54d33549 100644 (file)
@@ -119,6 +119,41 @@ func TestRouteMonitor(t *testing.T) {
        <-tmo
 }
 
+var parseInterfaceMessageTests = []*syscall.InterfaceMessage{
+       // with link-layer address
+       {
+               Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP},
+               Data: []uint8{
+                       0x11, 0x12, 0x2, 0x0, 0x6, 0x3, 0x6, 0x0,
+                       0x77, 0x6d, 0x31, 0x01, 0x23, 0x45, 0xab, 0xcd,
+                       0xef, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+               },
+       },
+       // without link-layer address
+       {
+               Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP},
+               Data: []uint8{
+                       0xe, 0x12, 0x4, 0x0, 0xf5, 0x6, 0x0, 0x0,
+                       0x70, 0x66, 0x6c, 0x6f, 0x67, 0x30, 0x0, 0x0,
+               },
+       },
+       // no data
+       {
+               Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP},
+               Data: []uint8{
+                       0x8, 0xa, 0xb, 0xc, 0xd, 0x0, 0x0, 0x0,
+               },
+       },
+}
+
+func TestParseInterfaceMessage(t *testing.T) {
+       for i, tt := range parseInterfaceMessageTests {
+               if _, err := syscall.ParseRoutingSockaddr(tt); err != nil {
+                       t.Errorf("#%d: %v", i, err)
+               }
+       }
+}
+
 type addrFamily byte
 
 func (f addrFamily) String() string {
index 34c707d9327e441206a17c2ff59d1c61c0a82ca0..bf32c987a9c868ca6fc005423f41289f9c0fcb59 100644 (file)
@@ -85,10 +85,10 @@ func UnixRights(fds ...int) []byte {
        h.Level = SOL_SOCKET
        h.Type = SCM_RIGHTS
        h.SetLen(CmsgLen(datalen))
-       data := uintptr(cmsgData(h))
+       data := cmsgData(h)
        for _, fd := range fds {
-               *(*int32)(unsafe.Pointer(data)) = int32(fd)
-               data += 4
+               *(*int32)(data) = int32(fd)
+               data = unsafe.Pointer(uintptr(data) + 4)
        }
        return b
 }
index ff09711ae0478453ca9bc7c24e2170a6cc95b892..7d42ad5dcecaddbc06c38c0f18f9d1483f44f0d9 100644 (file)
@@ -99,5 +99,8 @@ func (tv *Timeval) Nano() int64 {
 
 // use is a no-op, but the compiler cannot see that it is.
 // Calling use(p) ensures that p is kept live until that point.
+// This was needed until Go 1.6 to call syscall.Syscall correctly.
+// As of Go 1.6 the compiler handles that case automatically.
+// The uses and definition of use can be removed early in the Go 1.7 cycle.
 //go:noescape
 func use(p unsafe.Pointer)
diff --git a/libgo/go/syscall/syscall_linux_mips64x.go b/libgo/go/syscall/syscall_linux_mips64x.go
new file mode 100644 (file)
index 0000000..c1d51b1
--- /dev/null
@@ -0,0 +1,20 @@
+// 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 linux
+// +build mips64 mips64le
+
+package syscall
+
+func (r *PtraceRegs) PC() uint64 { return r.Regs[64] }
+
+func (r *PtraceRegs) SetPC(pc uint64) { r.Regs[64] = pc }
+
+func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) {
+       return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
+}
+
+func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) {
+       return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
+}
index 40fce6d68c6780388beee064d983f9330c9ec5e8..4cabf6c9c9055c1bd6aaeaaf54ab913a646cc94a 100644 (file)
@@ -66,11 +66,11 @@ func TestLinuxDeathSignal(t *testing.T) {
        cmd.Env = []string{"GO_DEATHSIG_PARENT=1"}
        chldStdin, err := cmd.StdinPipe()
        if err != nil {
-               t.Fatal("failed to create new stdin pipe: %v", err)
+               t.Fatalf("failed to create new stdin pipe: %v", err)
        }
        chldStdout, err := cmd.StdoutPipe()
        if err != nil {
-               t.Fatal("failed to create new stdout pipe: %v", err)
+               t.Fatalf("failed to create new stdout pipe: %v", err)
        }
        cmd.Stderr = os.Stderr
 
@@ -114,7 +114,7 @@ func deathSignalParent() {
 
        err := cmd.Start()
        if err != nil {
-               fmt.Fprintf(os.Stderr, "death signal parent error: %v\n")
+               fmt.Fprintf(os.Stderr, "death signal parent error: %v\n", err)
                os.Exit(1)
        }
        cmd.Wait()
index 21bf6eafb11976744c942d8b9c3f4717081ec2fb..c47050d2ad7040ba91ec2f25981f2de15e6a6490 100644 (file)
@@ -7,6 +7,7 @@
 package syscall
 
 import (
+       "internal/race"
        "runtime"
        "sync"
        "unsafe"
@@ -210,24 +211,30 @@ func (s Signal) String() string {
 
 func Read(fd int, p []byte) (n int, err error) {
        n, err = read(fd, p)
-       if raceenabled {
+       if race.Enabled {
                if n > 0 {
-                       raceWriteRange(unsafe.Pointer(&p[0]), n)
+                       race.WriteRange(unsafe.Pointer(&p[0]), n)
                }
                if err == nil {
-                       raceAcquire(unsafe.Pointer(&ioSync))
+                       race.Acquire(unsafe.Pointer(&ioSync))
                }
        }
+       if msanenabled && n > 0 {
+               msanWrite(unsafe.Pointer(&p[0]), n)
+       }
        return
 }
 
 func Write(fd int, p []byte) (n int, err error) {
-       if raceenabled {
-               raceReleaseMerge(unsafe.Pointer(&ioSync))
+       if race.Enabled {
+               race.ReleaseMerge(unsafe.Pointer(&ioSync))
        }
        n, err = write(fd, p)
-       if raceenabled && n > 0 {
-               raceReadRange(unsafe.Pointer(&p[0]), n)
+       if race.Enabled && n > 0 {
+               race.ReadRange(unsafe.Pointer(&p[0]), n)
+       }
+       if msanenabled && n > 0 {
+               msanRead(unsafe.Pointer(&p[0]), n)
        }
        return
 }
index 62e696d2214133222257178052432ac11fb8f845..85178c2f867adddfe7c22d9e34004430eb6a2bba 100644 (file)
@@ -33,6 +33,17 @@ type InternalBenchmark struct {
 
 // B is a type passed to Benchmark functions to manage benchmark
 // timing and to specify the number of iterations to run.
+//
+// A benchmark ends when its Benchmark function returns or calls any of the methods
+// FailNow, Fatal, Fatalf, SkipNow, Skip, or Skipf. Those methods must be called
+// only from the goroutine running the Benchmark function.
+// The other reporting methods, such as the variations of Log and Error,
+// may be called simultaneously from multiple goroutines.
+//
+// Like in tests, benchmark logs are accumulated during execution
+// and dumped to standard error when done. Unlike in tests, benchmark logs
+// are always printed, so as not to hide output whose existence may be
+// affecting benchmark results.
 type B struct {
        common
        N                int
index 13c56cdf4880035d05428aa67b9f225083ac91fd..187195c75907d7333bda9ab601c2009d4d2222a0 100644 (file)
@@ -52,8 +52,15 @@ const complexSize = 50
 // If the type implements the Generator interface, that will be used.
 // Note: To create arbitrary values for structs, all the fields must be exported.
 func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
+       return sizedValue(t, rand, complexSize)
+}
+
+// sizedValue returns an arbitrary value of the given type. The size
+// hint is used for shrinking as a function of indirection level so
+// that recursive data structures will terminate.
+func sizedValue(t reflect.Type, rand *rand.Rand, size int) (value reflect.Value, ok bool) {
        if m, ok := reflect.Zero(t).Interface().(Generator); ok {
-               return m.Generate(rand, complexSize), true
+               return m.Generate(rand, size), true
        }
 
        v := reflect.New(t).Elem()
@@ -91,21 +98,21 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
        case reflect.Uintptr:
                v.SetUint(uint64(randInt64(rand)))
        case reflect.Map:
-               numElems := rand.Intn(complexSize)
+               numElems := rand.Intn(size)
                v.Set(reflect.MakeMap(concrete))
                for i := 0; i < numElems; i++ {
-                       key, ok1 := Value(concrete.Key(), rand)
-                       value, ok2 := Value(concrete.Elem(), rand)
+                       key, ok1 := sizedValue(concrete.Key(), rand, size)
+                       value, ok2 := sizedValue(concrete.Elem(), rand, size)
                        if !ok1 || !ok2 {
                                return reflect.Value{}, false
                        }
                        v.SetMapIndex(key, value)
                }
        case reflect.Ptr:
-               if rand.Intn(complexSize) == 0 {
+               if rand.Intn(size) == 0 {
                        v.Set(reflect.Zero(concrete)) // Generate nil pointer.
                } else {
-                       elem, ok := Value(concrete.Elem(), rand)
+                       elem, ok := sizedValue(concrete.Elem(), rand, size)
                        if !ok {
                                return reflect.Value{}, false
                        }
@@ -113,10 +120,11 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
                        v.Elem().Set(elem)
                }
        case reflect.Slice:
-               numElems := rand.Intn(complexSize)
+               numElems := rand.Intn(size)
+               sizeLeft := size - numElems
                v.Set(reflect.MakeSlice(concrete, numElems, numElems))
                for i := 0; i < numElems; i++ {
-                       elem, ok := Value(concrete.Elem(), rand)
+                       elem, ok := sizedValue(concrete.Elem(), rand, sizeLeft)
                        if !ok {
                                return reflect.Value{}, false
                        }
@@ -124,7 +132,7 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
                }
        case reflect.Array:
                for i := 0; i < v.Len(); i++ {
-                       elem, ok := Value(concrete.Elem(), rand)
+                       elem, ok := sizedValue(concrete.Elem(), rand, size)
                        if !ok {
                                return reflect.Value{}, false
                        }
@@ -138,8 +146,16 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
                }
                v.SetString(string(codePoints))
        case reflect.Struct:
-               for i := 0; i < v.NumField(); i++ {
-                       elem, ok := Value(concrete.Field(i).Type, rand)
+               n := v.NumField()
+               // Divide sizeLeft evenly among the struct fields.
+               sizeLeft := size
+               if n > sizeLeft {
+                       sizeLeft = 1
+               } else if n > 0 {
+                       sizeLeft /= n
+               }
+               for i := 0; i < n; i++ {
+                       elem, ok := sizedValue(concrete.Field(i).Type, rand, sizeLeft)
                        if !ok {
                                return reflect.Value{}, false
                        }
index c79f30ea1dbee049ef71398d47ea4349526142c6..fe443592f87bed611c3957fde67fc56dcb295798 100644 (file)
@@ -259,16 +259,51 @@ func TestFailure(t *testing.T) {
        }
 }
 
-// The following test didn't terminate because nil pointers were not
-// generated.
-// Issue 8818.
-func TestNilPointers(t *testing.T) {
-       type Recursive struct {
-               Next *Recursive
+// Recursive data structures didn't terminate.
+// Issues 8818 and 11148.
+func TestRecursive(t *testing.T) {
+       type R struct {
+               Ptr      *R
+               SliceP   []*R
+               Slice    []R
+               Map      map[int]R
+               MapP     map[int]*R
+               MapR     map[*R]*R
+               SliceMap []map[int]R
        }
 
-       f := func(rec Recursive) bool {
-               return true
-       }
+       f := func(r R) bool { return true }
+       Check(f, nil)
+}
+
+func TestEmptyStruct(t *testing.T) {
+       f := func(struct{}) bool { return true }
+       Check(f, nil)
+}
+
+type (
+       A struct{ B *B }
+       B struct{ A *A }
+)
+
+func TestMutuallyRecursive(t *testing.T) {
+       f := func(a A) bool { return true }
        Check(f, nil)
 }
+
+// Some serialization formats (e.g. encoding/pem) cannot distinguish
+// between a nil and an empty map or slice, so avoid generating the
+// zero value for these.
+func TestNonZeroSliceAndMap(t *testing.T) {
+       type Q struct {
+               M map[int]int
+               S []int
+       }
+       f := func(q Q) bool {
+               return q.M != nil && q.S != nil
+       }
+       err := Check(f, nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+}
index 9ec3869768c9fe6ce04a05f35ad7290e642b2936..bcbe8f15c55a9ff645f6fdca6f5320a9ab235db2 100644 (file)
@@ -149,6 +149,7 @@ import (
        "fmt"
        "os"
        "runtime"
+       "runtime/debug"
        "runtime/pprof"
        "strconv"
        "strings"
@@ -281,9 +282,18 @@ var _ TB = (*B)(nil)
 
 // T is a type passed to Test functions to manage test state and support formatted test logs.
 // Logs are accumulated during execution and dumped to standard error when done.
+//
+// A test ends when its Test function returns or calls any of the methods
+// FailNow, Fatal, Fatalf, SkipNow, Skip, or Skipf. Those methods, as well as
+// the Parallel method, must be called only from the goroutine running the
+// Test function.
+//
+// The other reporting methods, such as the variations of Log and Error,
+// may be called simultaneously from multiple goroutines.
 type T struct {
        common
-       name          string    // Name of test.
+       name          string // Name of test.
+       isParallel    bool
        startParallel chan bool // Parallel tests will wait on this.
 }
 
@@ -417,10 +427,17 @@ func (c *common) Skipped() bool {
 // Parallel signals that this test is to be run in parallel with (and only with)
 // other parallel tests.
 func (t *T) Parallel() {
+       if t.isParallel {
+               panic("testing: t.Parallel called multiple times")
+       }
+       t.isParallel = true
+
+       // We don't want to include the time we spend waiting for serial tests
+       // in the test duration. Record the elapsed time thus far and reset the
+       // timer afterwards.
+       t.duration += time.Since(t.start)
        t.signal <- (*T)(nil) // Release main testing loop
        <-t.startParallel     // Wait for serial tests to finish
-       // Assuming Parallel is the first thing a test does, which is reasonable,
-       // reinitialize the test's start time because it's actually starting now.
        t.start = time.Now()
 }
 
@@ -437,7 +454,7 @@ func tRunner(t *T, test *InternalTest) {
        // a call to runtime.Goexit, record the duration and send
        // a signal saying that the test is done.
        defer func() {
-               t.duration = time.Now().Sub(t.start)
+               t.duration += time.Now().Sub(t.start)
                // If the test panicked, print any test output before dying.
                err := recover()
                if !t.finished && err == nil {
@@ -484,7 +501,11 @@ func MainStart(matchString func(pat, str string) (bool, error), tests []Internal
 
 // Run runs the tests. It returns an exit code to pass to os.Exit.
 func (m *M) Run() int {
-       flag.Parse()
+       // TestMain may have already called flag.Parse.
+       if !flag.Parsed() {
+               flag.Parse()
+       }
+
        parseCpuList()
 
        before()
@@ -704,6 +725,7 @@ var timer *time.Timer
 func startAlarm() {
        if *timeout > 0 {
                timer = time.AfterFunc(*timeout, func() {
+                       debug.SetTraceback("all")
                        panic(fmt.Sprintf("test timed out after %v", *timeout))
                })
        }
index 3ab01edd247ef4a97904c5e2e5610d66ff32438c..0155800f34a716d43352b3ca206c9c5f30fc69ae 100644 (file)
@@ -73,7 +73,7 @@ const (
        GoTokens       = ScanIdents | ScanFloats | ScanChars | ScanStrings | ScanRawStrings | ScanComments | SkipComments
 )
 
-// The result of Scan is one of the following tokens or a Unicode character.
+// The result of Scan is one of these tokens or a Unicode character.
 const (
        EOF = -(iota + 1)
        Ident
index 0ce63f66d59c5bcbd527a56afda803b708a99a96..df8c95f8c8949e7ec05b5e68f54d486598c06dec 100644 (file)
@@ -36,10 +36,35 @@ Here is a trivial example that prints "17 items are made of wool".
 
 More intricate examples appear below.
 
+Text and spaces
+
+By default, all text between actions is copied verbatim when the template is
+executed. For example, the string " items are made of " in the example above appears
+on standard output when the program is run.
+
+However, to aid in formatting template source code, if an action's left delimiter
+(by default "{{") is followed immediately by a minus sign and ASCII space character
+("{{- "), all trailing white space is trimmed from the immediately preceding text.
+Similarly, if the right delimiter ("}}") is preceded by a space and minus sign
+(" -}}"), all leading white space is trimmed from the immediately following text.
+In these trim markers, the ASCII space must be present; "{{-3}}" parses as an
+action containing the number -3.
+
+For instance, when executing the template whose source is
+
+       "{{23 -}} < {{- 45}}"
+
+the generated output would be
+
+       "23<45"
+
+For this trimming, the definition of white space characters is the same as in Go:
+space, horizontal tab, carriage return, and newline.
+
 Actions
 
 Here is the list of actions. "Arguments" and "pipelines" are evaluations of
-data, defined in detail below.
+data, defined in detail in the corresponding sections that follow.
 
 */
 //     {{/* a comment */}}
@@ -90,6 +115,14 @@ data, defined in detail below.
                The template with the specified name is executed with dot set
                to the value of the pipeline.
 
+       {{block "name" pipeline}} T1 {{end}}
+               A block is shorthand for defining a template
+                       {{define "name"}} T1 {{end}}
+               and then executing it in place
+                       {{template "name" .}}
+               The typical use is to define a set of root templates that are
+               then customized by redefining the block templates within.
+
        {{with pipeline}} T1 {{end}}
                If the value of the pipeline is empty, no output is generated;
                otherwise, dot is set to the value of the pipeline and T1 is
@@ -167,6 +200,8 @@ field of a struct, the function is not invoked automatically, but it
 can be used as a truth value for an if action and the like. To invoke
 it, use the call function, defined below.
 
+Pipelines
+
 A pipeline is a possibly chained sequence of "commands". A command is a simple
 value (argument) or a function or method call, possibly with multiple arguments:
 
@@ -184,8 +219,6 @@ value (argument) or a function or method call, possibly with multiple arguments:
                        function(Argument1, etc.)
                Functions and function names are described below.
 
-Pipelines
-
 A pipeline may be "chained" by separating a sequence of commands with pipeline
 characters '|'. In a chained pipeline, the result of the each command is
 passed as the last argument of the following command. The output of the final
index daba788b55bd56c111787d0b1372e7905aa1f5f5..efe1817173f5883d5979cc2682c78cf1a45b726b 100644 (file)
@@ -78,7 +78,23 @@ func doublePercent(str string) string {
        return str
 }
 
-// errorf formats the error and terminates processing.
+// TODO: It would be nice if ExecError was more broken down, but
+// the way ErrorContext embeds the template name makes the
+// processing too clumsy.
+
+// ExecError is the custom error type returned when Execute has an
+// error evaluating its template. (If a write error occurs, the actual
+// error is returned; it will not be of type ExecError.)
+type ExecError struct {
+       Name string // Name of template.
+       Err  error  // Pre-formatted error.
+}
+
+func (e ExecError) Error() string {
+       return e.Err.Error()
+}
+
+// errorf records an ExecError and terminates processing.
 func (s *state) errorf(format string, args ...interface{}) {
        name := doublePercent(s.tmpl.Name())
        if s.node == nil {
@@ -87,7 +103,24 @@ func (s *state) errorf(format string, args ...interface{}) {
                location, context := s.tmpl.ErrorContext(s.node)
                format = fmt.Sprintf("template: %s: executing %q at <%s>: %s", location, name, doublePercent(context), format)
        }
-       panic(fmt.Errorf(format, args...))
+       panic(ExecError{
+               Name: s.tmpl.Name(),
+               Err:  fmt.Errorf(format, args...),
+       })
+}
+
+// writeError is the wrapper type used internally when Execute has an
+// error writing to its output. We strip the wrapper in errRecover.
+// Note that this is not an implementation of error, so it cannot escape
+// from the package as an error value.
+type writeError struct {
+       Err error // Original error.
+}
+
+func (s *state) writeError(err error) {
+       panic(writeError{
+               Err: err,
+       })
 }
 
 // errRecover is the handler that turns panics into returns from the top
@@ -98,8 +131,10 @@ func errRecover(errp *error) {
                switch err := e.(type) {
                case runtime.Error:
                        panic(e)
-               case error:
-                       *errp = err
+               case writeError:
+                       *errp = err.Err // Strip the wrapper.
+               case ExecError:
+                       *errp = err // Keep the wrapper.
                default:
                        panic(e)
                }
@@ -145,7 +180,7 @@ func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
 }
 
 // DefinedTemplates returns a string listing the defined templates,
-// prefixed by the string "defined templates are: ". If there are none,
+// prefixed by the string "defined templates are: ". If there are none,
 // it returns the empty string. For generating an error message here
 // and in html/template.
 func (t *Template) DefinedTemplates() string {
@@ -193,7 +228,7 @@ func (s *state) walk(dot reflect.Value, node parse.Node) {
                s.walkTemplate(dot, node)
        case *parse.TextNode:
                if _, err := s.wr.Write(node.Text); err != nil {
-                       s.errorf("%s", err)
+                       s.writeError(err)
                }
        case *parse.WithNode:
                s.walkIfOrWith(parse.NodeWith, dot, node.Pipe, node.List, node.ElseList)
@@ -222,8 +257,13 @@ func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.
        }
 }
 
-// isTrue reports whether the value is 'true', in the sense of not the zero of its type,
-// and whether the value has a meaningful truth value.
+// IsTrue reports whether the value is 'true', in the sense of not the zero of its type,
+// and whether the value has a meaningful truth value. This is the definition of
+// truth used by if and other such actions.
+func IsTrue(val interface{}) (truth, ok bool) {
+       return isTrue(reflect.ValueOf(val))
+}
+
 func isTrue(val reflect.Value) (truth, ok bool) {
        if !val.IsValid() {
                // Something like var x interface{}, never set. It's a form of nil.
@@ -483,7 +523,7 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
                return zero
        }
        typ := receiver.Type()
-       receiver, = indirect(receiver)
+       receiver, isNil := indirect(receiver)
        // Unless it's an interface, need to get to a value of type *T to guarantee
        // we see all methods of T and *T.
        ptr := receiver
@@ -495,7 +535,6 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
        }
        hasArgs := len(args) > 1 || final.IsValid()
        // It's not a method; must be a field of a struct or an element of a map. The receiver must not be nil.
-       receiver, isNil := indirect(receiver)
        if isNil {
                s.errorf("nil pointer evaluating %s.%s", typ, fieldName)
        }
@@ -789,16 +828,11 @@ func (s *state) evalEmptyInterface(dot reflect.Value, n parse.Node) reflect.Valu
 }
 
 // indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
-// We indirect through pointers and empty interfaces (only) because
-// non-empty interfaces have methods we might need.
 func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
        for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
                if v.IsNil() {
                        return v, true
                }
-               if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
-                       break
-               }
        }
        return v, false
 }
@@ -811,7 +845,10 @@ func (s *state) printValue(n parse.Node, v reflect.Value) {
        if !ok {
                s.errorf("can't print %s of type %s", n, v.Type())
        }
-       fmt.Fprint(s.wr, iface)
+       _, err := fmt.Fprint(s.wr, iface)
+       if err != nil {
+               s.writeError(err)
+       }
 }
 
 // printableValue returns the, possibly indirected, interface value inside v that
index ba0e434f98cfeb15647ee794af4d027492a86b7e..e507e917fe51aa48b4e785b01aef3815b71aaf8f 100644 (file)
@@ -9,6 +9,7 @@ import (
        "errors"
        "flag"
        "fmt"
+       "io/ioutil"
        "reflect"
        "strings"
        "testing"
@@ -50,8 +51,9 @@ type T struct {
        Empty2 interface{}
        Empty3 interface{}
        Empty4 interface{}
-       // Non-empty interface.
-       NonEmptyInterface I
+       // Non-empty interfaces.
+       NonEmptyInterface    I
+       NonEmptyInterfacePtS *I
        // Stringer.
        Str fmt.Stringer
        Err error
@@ -72,6 +74,12 @@ type T struct {
        unexported int
 }
 
+type S []string
+
+func (S) Method0() string {
+       return "M0"
+}
+
 type U struct {
        V string
 }
@@ -98,6 +106,8 @@ func (w *W) Error() string {
        return fmt.Sprintf("[%d]", w.k)
 }
 
+var siVal = I(S{"a", "b"})
+
 var tVal = &T{
        True:   true,
        I:      17,
@@ -118,22 +128,23 @@ var tVal = &T{
                {"one": 1, "two": 2},
                {"eleven": 11, "twelve": 12},
        },
-       Empty1:            3,
-       Empty2:            "empty2",
-       Empty3:            []int{7, 8},
-       Empty4:            &U{"UinEmpty"},
-       NonEmptyInterface: new(T),
-       Str:               bytes.NewBuffer([]byte("foozle")),
-       Err:               errors.New("erroozle"),
-       PI:                newInt(23),
-       PS:                newString("a string"),
-       PSI:               newIntSlice(21, 22, 23),
-       BinaryFunc:        func(a, b string) string { return fmt.Sprintf("[%s=%s]", a, b) },
-       VariadicFunc:      func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") },
-       VariadicFuncInt:   func(a int, s ...string) string { return fmt.Sprint(a, "=<", strings.Join(s, "+"), ">") },
-       NilOKFunc:         func(s *int) bool { return s == nil },
-       ErrFunc:           func() (string, error) { return "bla", nil },
-       Tmpl:              Must(New("x").Parse("test template")), // "x" is the value of .X
+       Empty1:               3,
+       Empty2:               "empty2",
+       Empty3:               []int{7, 8},
+       Empty4:               &U{"UinEmpty"},
+       NonEmptyInterface:    &T{X: "x"},
+       NonEmptyInterfacePtS: &siVal,
+       Str:                  bytes.NewBuffer([]byte("foozle")),
+       Err:                  errors.New("erroozle"),
+       PI:                   newInt(23),
+       PS:                   newString("a string"),
+       PSI:                  newIntSlice(21, 22, 23),
+       BinaryFunc:           func(a, b string) string { return fmt.Sprintf("[%s=%s]", a, b) },
+       VariadicFunc:         func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") },
+       VariadicFuncInt:      func(a int, s ...string) string { return fmt.Sprint(a, "=<", strings.Join(s, "+"), ">") },
+       NilOKFunc:            func(s *int) bool { return s == nil },
+       ErrFunc:              func() (string, error) { return "bla", nil },
+       Tmpl:                 Must(New("x").Parse("test template")), // "x" is the value of .X
 }
 
 // A non-empty interface.
@@ -336,6 +347,7 @@ var execTests = []execTest{
        {"if not .BinaryFunc call", "{{ if not .BinaryFunc}}{{call .BinaryFunc `1` `2`}}{{else}}No{{end}}", "No", tVal, true},
        {"Interface Call", `{{stringer .S}}`, "foozle", map[string]interface{}{"S": bytes.NewBufferString("foozle")}, true},
        {".ErrFunc", "{{call .ErrFunc}}", "bla", tVal, true},
+       {"call nil", "{{call nil}}", "", tVal, false},
 
        // Erroneous function calls (check args).
        {".BinaryFuncTooFew", "{{call .BinaryFunc `1`}}", "", tVal, false},
@@ -424,12 +436,15 @@ var execTests = []execTest{
        {"slice[1]", "{{index .SI 1}}", "4", tVal, true},
        {"slice[HUGE]", "{{index .SI 10}}", "", tVal, false},
        {"slice[WRONG]", "{{index .SI `hello`}}", "", tVal, false},
+       {"slice[nil]", "{{index .SI nil}}", "", tVal, false},
        {"map[one]", "{{index .MSI `one`}}", "1", tVal, true},
        {"map[two]", "{{index .MSI `two`}}", "2", tVal, true},
        {"map[NO]", "{{index .MSI `XXX`}}", "0", tVal, true},
-       {"map[nil]", "{{index .MSI nil}}", "0", tVal, true},
+       {"map[nil]", "{{index .MSI nil}}", "", tVal, false},
+       {"map[``]", "{{index .MSI ``}}", "0", tVal, true},
        {"map[WRONG]", "{{index .MSI 10}}", "", tVal, false},
        {"double index", "{{index .SMSI 1 `eleven`}}", "11", tVal, true},
+       {"nil[1]", "{{index nil 1}}", "", tVal, false},
 
        // Len.
        {"slice", "{{len .SI}}", "3", tVal, true},
@@ -545,6 +560,11 @@ var execTests = []execTest{
        {"bug16i", "{{\"aaa\"|oneArg}}", "oneArg=aaa", tVal, true},
        {"bug16j", "{{1+2i|printf \"%v\"}}", "(1+2i)", tVal, true},
        {"bug16k", "{{\"aaa\"|printf }}", "aaa", tVal, true},
+       {"bug17a", "{{.NonEmptyInterface.X}}", "x", tVal, true},
+       {"bug17b", "-{{.NonEmptyInterface.Method1 1234}}-", "-1234-", tVal, true},
+       {"bug17c", "{{len .NonEmptyInterfacePtS}}", "2", tVal, true},
+       {"bug17d", "{{index .NonEmptyInterfacePtS 0}}", "a", tVal, true},
+       {"bug17e", "{{range .NonEmptyInterfacePtS}}-{{.}}-{{end}}", "-a--b-", tVal, true},
 }
 
 func zeroArgs() string {
@@ -796,18 +816,19 @@ type Tree struct {
 }
 
 // Use different delimiters to test Set.Delims.
+// Also test the trimming of leading and trailing spaces.
 const treeTemplate = `
-       (define "tree")
+       (- define "tree" -)
        [
-               (.Val)
-               (with .Left)
-                       (template "tree" .)
-               (end)
-               (with .Right)
-                       (template "tree" .)
-               (end)
+               (- .Val -)
+               (- with .Left -)
+                       (template "tree" . -)
+               (- end -)
+               (- with .Right -)
+                       (- template "tree" . -)
+               (- end -)
        ]
-       (end)
+       (- end -)
 `
 
 func TestTree(t *testing.T) {
@@ -852,19 +873,13 @@ func TestTree(t *testing.T) {
                t.Fatal("parse error:", err)
        }
        var b bytes.Buffer
-       stripSpace := func(r rune) rune {
-               if r == '\t' || r == '\n' {
-                       return -1
-               }
-               return r
-       }
        const expect = "[1[2[3[4]][5[6]]][7[8[9]][10[11]]]]"
        // First by looking up the template.
        err = tmpl.Lookup("tree").Execute(&b, tree)
        if err != nil {
                t.Fatal("exec error:", err)
        }
-       result := strings.Map(stripSpace, b.String())
+       result := b.String()
        if result != expect {
                t.Errorf("expected %q got %q", expect, result)
        }
@@ -874,7 +889,7 @@ func TestTree(t *testing.T) {
        if err != nil {
                t.Fatal("exec error:", err)
        }
-       result = strings.Map(stripSpace, b.String())
+       result = b.String()
        if result != expect {
                t.Errorf("expected %q got %q", expect, result)
        }
@@ -1141,3 +1156,127 @@ func TestUnterminatedStringError(t *testing.T) {
                t.Fatalf("unexpected error: %s", str)
        }
 }
+
+const alwaysErrorText = "always be failing"
+
+var alwaysError = errors.New(alwaysErrorText)
+
+type ErrorWriter int
+
+func (e ErrorWriter) Write(p []byte) (int, error) {
+       return 0, alwaysError
+}
+
+func TestExecuteGivesExecError(t *testing.T) {
+       // First, a non-execution error shouldn't be an ExecError.
+       tmpl, err := New("X").Parse("hello")
+       if err != nil {
+               t.Fatal(err)
+       }
+       err = tmpl.Execute(ErrorWriter(0), 0)
+       if err == nil {
+               t.Fatal("expected error; got none")
+       }
+       if err.Error() != alwaysErrorText {
+               t.Errorf("expected %q error; got %q", alwaysErrorText, err)
+       }
+       // This one should be an ExecError.
+       tmpl, err = New("X").Parse("hello, {{.X.Y}}")
+       if err != nil {
+               t.Fatal(err)
+       }
+       err = tmpl.Execute(ioutil.Discard, 0)
+       if err == nil {
+               t.Fatal("expected error; got none")
+       }
+       eerr, ok := err.(ExecError)
+       if !ok {
+               t.Fatalf("did not expect ExecError %s", eerr)
+       }
+       expect := "field X in type int"
+       if !strings.Contains(err.Error(), expect) {
+               t.Errorf("expected %q; got %q", expect, err)
+       }
+}
+
+func funcNameTestFunc() int {
+       return 0
+}
+
+func TestGoodFuncNames(t *testing.T) {
+       names := []string{
+               "_",
+               "a",
+               "a1",
+               "a1",
+               "Ӵ",
+       }
+       for _, name := range names {
+               tmpl := New("X").Funcs(
+                       FuncMap{
+                               name: funcNameTestFunc,
+                       },
+               )
+               if tmpl == nil {
+                       t.Fatalf("nil result for %q", name)
+               }
+       }
+}
+
+func TestBadFuncNames(t *testing.T) {
+       names := []string{
+               "",
+               "2",
+               "a-b",
+       }
+       for _, name := range names {
+               testBadFuncName(name, t)
+       }
+}
+
+func testBadFuncName(name string, t *testing.T) {
+       defer func() {
+               recover()
+       }()
+       New("X").Funcs(
+               FuncMap{
+                       name: funcNameTestFunc,
+               },
+       )
+       // If we get here, the name did not cause a panic, which is how Funcs
+       // reports an error.
+       t.Errorf("%q succeeded incorrectly as function name", name)
+}
+
+func TestBlock(t *testing.T) {
+       const (
+               input   = `a({{block "inner" .}}bar({{.}})baz{{end}})b`
+               want    = `a(bar(hello)baz)b`
+               overlay = `{{define "inner"}}foo({{.}})bar{{end}}`
+               want2   = `a(foo(goodbye)bar)b`
+       )
+       tmpl, err := New("outer").Parse(input)
+       if err != nil {
+               t.Fatal(err)
+       }
+       tmpl2, err := Must(tmpl.Clone()).Parse(overlay)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       var buf bytes.Buffer
+       if err := tmpl.Execute(&buf, "hello"); err != nil {
+               t.Fatal(err)
+       }
+       if got := buf.String(); got != want {
+               t.Errorf("got %q, want %q", got, want)
+       }
+
+       buf.Reset()
+       if err := tmpl2.Execute(&buf, "goodbye"); err != nil {
+               t.Fatal(err)
+       }
+       if got := buf.String(); got != want2 {
+               t.Errorf("got %q, want %q", got, want2)
+       }
+}
index ccd0dfc80d86b024a9759dddcdf82520cffc680b..49e9e7419a49f58624655c1a12a8e2407e3589e4 100644 (file)
@@ -58,6 +58,9 @@ func createValueFuncs(funcMap FuncMap) map[string]reflect.Value {
 // addValueFuncs adds to values the functions in funcs, converting them to reflect.Values.
 func addValueFuncs(out map[string]reflect.Value, in FuncMap) {
        for name, fn := range in {
+               if !goodName(name) {
+                       panic(fmt.Errorf("function name %s is not a valid identifier", name))
+               }
                v := reflect.ValueOf(fn)
                if v.Kind() != reflect.Func {
                        panic("value for " + name + " not a function")
@@ -77,7 +80,7 @@ func addFuncs(out, in FuncMap) {
        }
 }
 
-// goodFunc checks that the function or method has the right result signature.
+// goodFunc reports whether the function or method has the right result signature.
 func goodFunc(typ reflect.Type) bool {
        // We allow functions with 1 result or 2 results where the second is an error.
        switch {
@@ -89,6 +92,23 @@ func goodFunc(typ reflect.Type) bool {
        return false
 }
 
+// goodName reports whether the function name is a valid identifier.
+func goodName(name string) bool {
+       if name == "" {
+               return false
+       }
+       for i, r := range name {
+               switch {
+               case r == '_':
+               case i == 0 && !unicode.IsLetter(r):
+                       return false
+               case !unicode.IsLetter(r) && !unicode.IsDigit(r):
+                       return false
+               }
+       }
+       return true
+}
+
 // findFunction looks for a function in the template, and global map.
 func findFunction(name string, tmpl *Template) (reflect.Value, bool) {
        if tmpl != nil && tmpl.common != nil {
@@ -104,6 +124,21 @@ func findFunction(name string, tmpl *Template) (reflect.Value, bool) {
        return reflect.Value{}, false
 }
 
+// prepareArg checks if value can be used as an argument of type argType, and
+// converts an invalid value to appropriate zero if possible.
+func prepareArg(value reflect.Value, argType reflect.Type) (reflect.Value, error) {
+       if !value.IsValid() {
+               if !canBeNil(argType) {
+                       return reflect.Value{}, fmt.Errorf("value is nil; should be of type %s", argType)
+               }
+               value = reflect.Zero(argType)
+       }
+       if !value.Type().AssignableTo(argType) {
+               return reflect.Value{}, fmt.Errorf("value has type %s; should be %s", value.Type(), argType)
+       }
+       return value, nil
+}
+
 // Indexing.
 
 // index returns the result of indexing its first argument by the following
@@ -111,6 +146,9 @@ func findFunction(name string, tmpl *Template) (reflect.Value, bool) {
 // indexed item must be a map, slice, or array.
 func index(item interface{}, indices ...interface{}) (interface{}, error) {
        v := reflect.ValueOf(item)
+       if !v.IsValid() {
+               return nil, fmt.Errorf("index of untyped nil")
+       }
        for _, i := range indices {
                index := reflect.ValueOf(i)
                var isNil bool
@@ -125,6 +163,8 @@ func index(item interface{}, indices ...interface{}) (interface{}, error) {
                                x = index.Int()
                        case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
                                x = int64(index.Uint())
+                       case reflect.Invalid:
+                               return nil, fmt.Errorf("cannot index slice/array with nil")
                        default:
                                return nil, fmt.Errorf("cannot index slice/array with type %s", index.Type())
                        }
@@ -133,17 +173,18 @@ func index(item interface{}, indices ...interface{}) (interface{}, error) {
                        }
                        v = v.Index(int(x))
                case reflect.Map:
-                       if !index.IsValid() {
-                               index = reflect.Zero(v.Type().Key())
-                       }
-                       if !index.Type().AssignableTo(v.Type().Key()) {
-                               return nil, fmt.Errorf("%s is not index type for %s", index.Type(), v.Type())
+                       index, err := prepareArg(index, v.Type().Key())
+                       if err != nil {
+                               return nil, err
                        }
                        if x := v.MapIndex(index); x.IsValid() {
                                v = x
                        } else {
                                v = reflect.Zero(v.Type().Elem())
                        }
+               case reflect.Invalid:
+                       // the loop holds invariant: v.IsValid()
+                       panic("unreachable")
                default:
                        return nil, fmt.Errorf("can't index item of type %s", v.Type())
                }
@@ -155,7 +196,11 @@ func index(item interface{}, indices ...interface{}) (interface{}, error) {
 
 // length returns the length of the item, with an error if it has no defined length.
 func length(item interface{}) (int, error) {
-       v, isNil := indirect(reflect.ValueOf(item))
+       v := reflect.ValueOf(item)
+       if !v.IsValid() {
+               return 0, fmt.Errorf("len of untyped nil")
+       }
+       v, isNil := indirect(v)
        if isNil {
                return 0, fmt.Errorf("len of nil pointer")
        }
@@ -172,6 +217,9 @@ func length(item interface{}) (int, error) {
 // The function must return 1 result, or 2 results, the second of which is an error.
 func call(fn interface{}, args ...interface{}) (interface{}, error) {
        v := reflect.ValueOf(fn)
+       if !v.IsValid() {
+               return nil, fmt.Errorf("call of nil")
+       }
        typ := v.Type()
        if typ.Kind() != reflect.Func {
                return nil, fmt.Errorf("non-function of type %s", typ)
@@ -201,13 +249,11 @@ func call(fn interface{}, args ...interface{}) (interface{}, error) {
                } else {
                        argType = dddType
                }
-               if !value.IsValid() && canBeNil(argType) {
-                       value = reflect.Zero(argType)
-               }
-               if !value.Type().AssignableTo(argType) {
-                       return nil, fmt.Errorf("arg %d has type %s; should be %s", i, value.Type(), argType)
+
+               var err error
+               if argv[i], err = prepareArg(value, argType); err != nil {
+                       return nil, fmt.Errorf("arg %d: %s", i, err)
                }
-               argv[i] = value
        }
        result := v.Call(argv)
        if len(result) == 2 && !result[1].IsNil() {
@@ -219,7 +265,7 @@ func call(fn interface{}, args ...interface{}) (interface{}, error) {
 // Boolean logic.
 
 func truth(a interface{}) bool {
-       t, _ := isTrue(reflect.ValueOf(a))
+       t, _ := IsTrue(a)
        return t
 }
 
@@ -254,9 +300,8 @@ func or(arg0 interface{}, args ...interface{}) interface{} {
 }
 
 // not returns the Boolean negation of its argument.
-func not(arg interface{}) (truth bool) {
-       truth, _ = isTrue(reflect.ValueOf(arg))
-       return !truth
+func not(arg interface{}) bool {
+       return !truth(arg)
 }
 
 // Comparison.
index ea01875e9c0664ce874c408fce8d76e1350fb0c6..a8342f50aa527e36c6f723feed9fe84afb15563e 100644 (file)
@@ -9,7 +9,6 @@ package template
 import (
        "bytes"
        "fmt"
-       "strings"
        "testing"
        "text/template/parse"
 )
@@ -277,17 +276,11 @@ func TestRedefinition(t *testing.T) {
        if tmpl, err = New("tmpl1").Parse(`{{define "test"}}foo{{end}}`); err != nil {
                t.Fatalf("parse 1: %v", err)
        }
-       if _, err = tmpl.Parse(`{{define "test"}}bar{{end}}`); err == nil {
-               t.Fatal("expected error")
+       if _, err = tmpl.Parse(`{{define "test"}}bar{{end}}`); err != nil {
+               t.Fatalf("got error %v, expected nil", err)
        }
-       if !strings.Contains(err.Error(), "redefinition") {
-               t.Fatalf("expected redefinition error; got %v", err)
-       }
-       if _, err = tmpl.New("tmpl2").Parse(`{{define "test"}}bar{{end}}`); err == nil {
-               t.Fatal("expected error")
-       }
-       if !strings.Contains(err.Error(), "redefinition") {
-               t.Fatalf("expected redefinition error; got %v", err)
+       if _, err = tmpl.New("tmpl2").Parse(`{{define "test"}}bar{{end}}`); err != nil {
+               t.Fatalf("got error %v, expected nil", err)
        }
 }
 
@@ -345,7 +338,6 @@ func TestNew(t *testing.T) {
 func TestParse(t *testing.T) {
        // In multiple calls to Parse with the same receiver template, only one call
        // can contain text other than space, comments, and template definitions
-       var err error
        t1 := New("test")
        if _, err := t1.Parse(`{{define "test"}}{{end}}`); err != nil {
                t.Fatalf("parsing test: %s", err)
@@ -356,10 +348,4 @@ func TestParse(t *testing.T) {
        if _, err := t1.Parse(`{{define "test"}}foo{{end}}`); err != nil {
                t.Fatalf("parsing test: %s", err)
        }
-       if _, err = t1.Parse(`{{define "test"}}foo{{end}}`); err == nil {
-               t.Fatal("no error from redefining a template")
-       }
-       if !strings.Contains(err.Error(), "redefinition") {
-               t.Fatalf("expected redefinition error; got %v", err)
-       }
 }
index 8f9fe1d4d8e48123604a23585a96ac6d5816db5b..ea93e051425441bd5f92c81078b29f069bfa7f01 100644 (file)
@@ -58,6 +58,7 @@ const (
        itemVariable   // variable starting with '$', such as '$' or  '$1' or '$hello'
        // Keywords appear after all the rest.
        itemKeyword  // used only to delimit the keywords
+       itemBlock    // block keyword
        itemDot      // the cursor, spelled '.'
        itemDefine   // define keyword
        itemElse     // else keyword
@@ -71,6 +72,7 @@ const (
 
 var key = map[string]itemType{
        ".":        itemDot,
+       "block":    itemBlock,
        "define":   itemDefine,
        "else":     itemElse,
        "end":      itemEnd,
@@ -83,6 +85,21 @@ var key = map[string]itemType{
 
 const eof = -1
 
+// Trimming spaces.
+// If the action begins "{{- " rather than "{{", then all space/tab/newlines
+// preceding the action are trimmed; conversely if it ends " -}}" the
+// leading spaces are trimmed. This is done entirely in the lexer; the
+// parser never sees it happen. We require an ASCII space to be
+// present to avoid ambiguity with things like "{{-3}}". It reads
+// better with the space present anyway. For simplicity, only ASCII
+// space does the job.
+const (
+       spaceChars      = " \t\r\n" // These are the space characters defined by Go itself.
+       leftTrimMarker  = "- "      // Attached to left delimiter, trims trailing spaces from preceding text.
+       rightTrimMarker = " -"      // Attached to right delimiter, trims leading spaces from following text.
+       trimMarkerLen   = Pos(len(leftTrimMarker))
+)
+
 // stateFn represents the state of the scanner as a function that returns the next state.
 type stateFn func(*lexer) stateFn
 
@@ -220,10 +237,18 @@ const (
 // lexText scans until an opening action delimiter, "{{".
 func lexText(l *lexer) stateFn {
        for {
-               if strings.HasPrefix(l.input[l.pos:], l.leftDelim) {
+               delim, trimSpace := l.atLeftDelim()
+               if delim {
+                       trimLength := Pos(0)
+                       if trimSpace {
+                               trimLength = rightTrimLength(l.input[l.start:l.pos])
+                       }
+                       l.pos -= trimLength
                        if l.pos > l.start {
                                l.emit(itemText)
                        }
+                       l.pos += trimLength
+                       l.ignore()
                        return lexLeftDelim
                }
                if l.next() == eof {
@@ -238,13 +263,56 @@ func lexText(l *lexer) stateFn {
        return nil
 }
 
-// lexLeftDelim scans the left delimiter, which is known to be present.
+// atLeftDelim reports whether the lexer is at a left delimiter, possibly followed by a trim marker.
+func (l *lexer) atLeftDelim() (delim, trimSpaces bool) {
+       if !strings.HasPrefix(l.input[l.pos:], l.leftDelim) {
+               return false, false
+       }
+       // The left delim might have the marker afterwards.
+       trimSpaces = strings.HasPrefix(l.input[l.pos+Pos(len(l.leftDelim)):], leftTrimMarker)
+       return true, trimSpaces
+}
+
+// rightTrimLength returns the length of the spaces at the end of the string.
+func rightTrimLength(s string) Pos {
+       return Pos(len(s) - len(strings.TrimRight(s, spaceChars)))
+}
+
+// atRightDelim reports whether the lexer is at a right delimiter, possibly preceded by a trim marker.
+func (l *lexer) atRightDelim() (delim, trimSpaces bool) {
+       if strings.HasPrefix(l.input[l.pos:], l.rightDelim) {
+               return true, false
+       }
+       // The right delim might have the marker before.
+       if strings.HasPrefix(l.input[l.pos:], rightTrimMarker) {
+               if strings.HasPrefix(l.input[l.pos+trimMarkerLen:], l.rightDelim) {
+                       return true, true
+               }
+       }
+       return false, false
+}
+
+// leftTrimLength returns the length of the spaces at the beginning of the string.
+func leftTrimLength(s string) Pos {
+       return Pos(len(s) - len(strings.TrimLeft(s, spaceChars)))
+}
+
+// lexLeftDelim scans the left delimiter, which is known to be present, possibly with a trim marker.
 func lexLeftDelim(l *lexer) stateFn {
        l.pos += Pos(len(l.leftDelim))
-       if strings.HasPrefix(l.input[l.pos:], leftComment) {
+       trimSpace := strings.HasPrefix(l.input[l.pos:], leftTrimMarker)
+       afterMarker := Pos(0)
+       if trimSpace {
+               afterMarker = trimMarkerLen
+       }
+       if strings.HasPrefix(l.input[l.pos+afterMarker:], leftComment) {
+               l.pos += afterMarker
+               l.ignore()
                return lexComment
        }
        l.emit(itemLeftDelim)
+       l.pos += afterMarker
+       l.ignore()
        l.parenDepth = 0
        return lexInsideAction
 }
@@ -257,19 +325,34 @@ func lexComment(l *lexer) stateFn {
                return l.errorf("unclosed comment")
        }
        l.pos += Pos(i + len(rightComment))
-       if !strings.HasPrefix(l.input[l.pos:], l.rightDelim) {
+       delim, trimSpace := l.atRightDelim()
+       if !delim {
                return l.errorf("comment ends before closing delimiter")
-
+       }
+       if trimSpace {
+               l.pos += trimMarkerLen
        }
        l.pos += Pos(len(l.rightDelim))
+       if trimSpace {
+               l.pos += leftTrimLength(l.input[l.pos:])
+       }
        l.ignore()
        return lexText
 }
 
-// lexRightDelim scans the right delimiter, which is known to be present.
+// lexRightDelim scans the right delimiter, which is known to be present, possibly with a trim marker.
 func lexRightDelim(l *lexer) stateFn {
+       trimSpace := strings.HasPrefix(l.input[l.pos:], rightTrimMarker)
+       if trimSpace {
+               l.pos += trimMarkerLen
+               l.ignore()
+       }
        l.pos += Pos(len(l.rightDelim))
        l.emit(itemRightDelim)
+       if trimSpace {
+               l.pos += leftTrimLength(l.input[l.pos:])
+               l.ignore()
+       }
        return lexText
 }
 
@@ -278,7 +361,8 @@ func lexInsideAction(l *lexer) stateFn {
        // Either number, quoted string, or identifier.
        // Spaces separate arguments; runs of spaces turn into itemSpace.
        // Pipe symbols separate and are emitted.
-       if strings.HasPrefix(l.input[l.pos:], l.rightDelim) {
+       delim, _ := l.atRightDelim()
+       if delim {
                if l.parenDepth == 0 {
                        return lexRightDelim
                }
index be551d87803228916a661c6333b07433e517f95a..e35ebf1a854ba5ed99987f5e395e50f289575c64 100644 (file)
@@ -33,6 +33,7 @@ var itemName = map[itemType]string{
 
        // keywords
        itemDot:      ".",
+       itemBlock:    "block",
        itemDefine:   "define",
        itemElse:     "else",
        itemIf:       "if",
@@ -58,6 +59,8 @@ type lexTest struct {
 }
 
 var (
+       tDot        = item{itemDot, 0, "."}
+       tBlock      = item{itemBlock, 0, "block"}
        tEOF        = item{itemEOF, 0, ""}
        tFor        = item{itemIdentifier, 0, "for"}
        tLeft       = item{itemLeftDelim, 0, "{{"}
@@ -104,6 +107,9 @@ var lexTests = []lexTest{
        }},
        {"empty action", `{{}}`, []item{tLeft, tRight, tEOF}},
        {"for", `{{for}}`, []item{tLeft, tFor, tRight, tEOF}},
+       {"block", `{{block "foo" .}}`, []item{
+               tLeft, tBlock, tSpace, {itemString, 0, `"foo"`}, tSpace, tDot, tRight, tEOF,
+       }},
        {"quote", `{{"abc \n\t\" "}}`, []item{tLeft, tQuote, tRight, tEOF}},
        {"raw quote", "{{" + raw + "}}", []item{tLeft, tRawQuote, tRight, tEOF}},
        {"raw quote with newline", "{{" + rawNL + "}}", []item{tLeft, tRawQuoteNL, tRight, tEOF}},
@@ -155,7 +161,7 @@ var lexTests = []lexTest{
        }},
        {"dot", "{{.}}", []item{
                tLeft,
-               {itemDot, 0, "."},
+               tDot,
                tRight,
                tEOF,
        }},
@@ -169,7 +175,7 @@ var lexTests = []lexTest{
                tLeft,
                {itemField, 0, ".x"},
                tSpace,
-               {itemDot, 0, "."},
+               tDot,
                tSpace,
                {itemNumber, 0, ".2"},
                tSpace,
@@ -278,6 +284,19 @@ var lexTests = []lexTest{
                tRight,
                tEOF,
        }},
+       {"trimming spaces before and after", "hello- {{- 3 -}} -world", []item{
+               {itemText, 0, "hello-"},
+               tLeft,
+               {itemNumber, 0, "3"},
+               tRight,
+               {itemText, 0, "-world"},
+               tEOF,
+       }},
+       {"trimming spaces before and after comment", "hello- {{- /* hello */ -}} -world", []item{
+               {itemText, 0, "hello-"},
+               {itemText, 0, "-world"},
+               tEOF,
+       }},
        // errors
        {"badchar", "#{{\x01}}", []item{
                {itemText, 0, "#"},
@@ -339,7 +358,7 @@ var lexTests = []lexTest{
                {itemText, 0, "hello-"},
                {itemError, 0, `unclosed comment`},
        }},
-       {"text with comment close separted from delim", "hello-{{/* */ }}-world", []item{
+       {"text with comment close separated from delim", "hello-{{/* */ }}-world", []item{
                {itemText, 0, "hello-"},
                {itemError, 0, `comment ends before closing delimiter`},
        }},
@@ -488,9 +507,9 @@ func TestShutdown(t *testing.T) {
 func (t *Tree) parseLexer(lex *lexer, text string) (tree *Tree, err error) {
        defer t.recover(&err)
        t.ParseName = t.Name
-       t.startParse(nil, lex)
-       t.parse(nil)
-       t.add(nil)
+       t.startParse(nil, lex, map[string]*Tree{})
+       t.parse()
+       t.add()
        t.stopParse()
        return t, nil
 }
index 88aacd1b72b55a37bf7f747bc7971d26b1c1cde4..dc56cf7aa0c55900d98b175218b0f1edd41408e1 100644 (file)
@@ -28,6 +28,7 @@ type Tree struct {
        token     [3]item // three-token lookahead for parser.
        peekCount int
        vars      []string // variables defined at the moment.
+       treeSet   map[string]*Tree
 }
 
 // Copy returns a copy of the Tree. Any parsing state is discarded.
@@ -205,11 +206,12 @@ func (t *Tree) recover(errp *error) {
 }
 
 // startParse initializes the parser, using the lexer.
-func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer) {
+func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer, treeSet map[string]*Tree) {
        t.Root = nil
        t.lex = lex
        t.vars = []string{"$"}
        t.funcs = funcs
+       t.treeSet = treeSet
 }
 
 // stopParse terminates parsing.
@@ -217,6 +219,7 @@ func (t *Tree) stopParse() {
        t.lex = nil
        t.vars = nil
        t.funcs = nil
+       t.treeSet = nil
 }
 
 // Parse parses the template definition string to construct a representation of
@@ -226,19 +229,19 @@ func (t *Tree) stopParse() {
 func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) {
        defer t.recover(&err)
        t.ParseName = t.Name
-       t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim))
+       t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim), treeSet)
        t.text = text
-       t.parse(treeSet)
-       t.add(treeSet)
+       t.parse()
+       t.add()
        t.stopParse()
        return t, nil
 }
 
-// add adds tree to the treeSet.
-func (t *Tree) add(treeSet map[string]*Tree) {
-       tree := treeSet[t.Name]
+// add adds tree to t.treeSet.
+func (t *Tree) add() {
+       tree := t.treeSet[t.Name]
        if tree == nil || IsEmptyTree(tree.Root) {
-               treeSet[t.Name] = t
+               t.treeSet[t.Name] = t
                return
        }
        if !IsEmptyTree(t.Root) {
@@ -274,7 +277,7 @@ func IsEmptyTree(n Node) bool {
 // parse is the top-level parser for a template, essentially the same
 // as itemList except it also parses {{define}} actions.
 // It runs to EOF.
-func (t *Tree) parse(treeSet map[string]*Tree) (next Node) {
+func (t *Tree) parse() (next Node) {
        t.Root = t.newList(t.peek().pos)
        for t.peek().typ != itemEOF {
                if t.peek().typ == itemLeftDelim {
@@ -283,8 +286,8 @@ func (t *Tree) parse(treeSet map[string]*Tree) (next Node) {
                                newT := New("definition") // name will be updated once we know it.
                                newT.text = t.text
                                newT.ParseName = t.ParseName
-                               newT.startParse(t.funcs, t.lex)
-                               newT.parseDefinition(treeSet)
+                               newT.startParse(t.funcs, t.lex, t.treeSet)
+                               newT.parseDefinition()
                                continue
                        }
                        t.backup2(delim)
@@ -300,9 +303,9 @@ func (t *Tree) parse(treeSet map[string]*Tree) (next Node) {
 }
 
 // parseDefinition parses a {{define}} ...  {{end}} template definition and
-// installs the definition in the treeSet map.  The "define" keyword has already
+// installs the definition in t.treeSet. The "define" keyword has already
 // been scanned.
-func (t *Tree) parseDefinition(treeSet map[string]*Tree) {
+func (t *Tree) parseDefinition() {
        const context = "define clause"
        name := t.expectOneOf(itemString, itemRawString, context)
        var err error
@@ -316,7 +319,7 @@ func (t *Tree) parseDefinition(treeSet map[string]*Tree) {
        if end.Type() != nodeEnd {
                t.errorf("unexpected %s in %s", end, context)
        }
-       t.add(treeSet)
+       t.add()
        t.stopParse()
 }
 
@@ -358,6 +361,8 @@ func (t *Tree) textOrAction() Node {
 // First word could be a keyword such as range.
 func (t *Tree) action() (n Node) {
        switch token := t.nextNonSpace(); token.typ {
+       case itemBlock:
+               return t.blockControl()
        case itemElse:
                return t.elseControl()
        case itemEnd:
@@ -522,13 +527,51 @@ func (t *Tree) elseControl() Node {
        return t.newElse(t.expect(itemRightDelim, "else").pos, t.lex.lineNumber())
 }
 
+// Block:
+//     {{block stringValue pipeline}}
+// Block keyword is past.
+// The name must be something that can evaluate to a string.
+// The pipeline is mandatory.
+func (t *Tree) blockControl() Node {
+       const context = "block clause"
+
+       token := t.nextNonSpace()
+       name := t.parseTemplateName(token, context)
+       pipe := t.pipeline(context)
+
+       block := New(name) // name will be updated once we know it.
+       block.text = t.text
+       block.ParseName = t.ParseName
+       block.startParse(t.funcs, t.lex, t.treeSet)
+       var end Node
+       block.Root, end = block.itemList()
+       if end.Type() != nodeEnd {
+               t.errorf("unexpected %s in %s", end, context)
+       }
+       block.add()
+       block.stopParse()
+
+       return t.newTemplate(token.pos, t.lex.lineNumber(), name, pipe)
+}
+
 // Template:
 //     {{template stringValue pipeline}}
 // Template keyword is past.  The name must be something that can evaluate
 // to a string.
 func (t *Tree) templateControl() Node {
-       var name string
+       const context = "template clause"
        token := t.nextNonSpace()
+       name := t.parseTemplateName(token, context)
+       var pipe *PipeNode
+       if t.nextNonSpace().typ != itemRightDelim {
+               t.backup()
+               // Do not pop variables; they persist until "end".
+               pipe = t.pipeline(context)
+       }
+       return t.newTemplate(token.pos, t.lex.lineNumber(), name, pipe)
+}
+
+func (t *Tree) parseTemplateName(token item, context string) (name string) {
        switch token.typ {
        case itemString, itemRawString:
                s, err := strconv.Unquote(token.val)
@@ -537,15 +580,9 @@ func (t *Tree) templateControl() Node {
                }
                name = s
        default:
-               t.unexpected(token, "template invocation")
-       }
-       var pipe *PipeNode
-       if t.nextNonSpace().typ != itemRightDelim {
-               t.backup()
-               // Do not pop variables; they persist until "end".
-               pipe = t.pipeline("template")
+               t.unexpected(token, context)
        }
-       return t.newTemplate(token.pos, t.lex.lineNumber(), name, pipe)
+       return
 }
 
 // command:
index 200d50c194dbd0cf2da3a8fd2fe18f227566e58d..b4512d3160045624fd8660277644d6744e76e128 100644 (file)
@@ -228,6 +228,15 @@ var parseTests = []parseTest{
                `{{with .X}}"hello"{{end}}`},
        {"with with else", "{{with .X}}hello{{else}}goodbye{{end}}", noError,
                `{{with .X}}"hello"{{else}}"goodbye"{{end}}`},
+       // Trimming spaces.
+       {"trim left", "x \r\n\t{{- 3}}", noError, `"x"{{3}}`},
+       {"trim right", "{{3 -}}\n\n\ty", noError, `{{3}}"y"`},
+       {"trim left and right", "x \r\n\t{{- 3 -}}\n\n\ty", noError, `"x"{{3}}"y"`},
+       {"comment trim left", "x \r\n\t{{- /* hi */}}", noError, `"x"`},
+       {"comment trim right", "{{/* hi */ -}}\n\n\ty", noError, `"y"`},
+       {"comment trim left and right", "x \r\n\t{{- /* */ -}}\n\n\ty", noError, `"x""y"`},
+       {"block definition", `{{block "foo" .}}hello{{end}}`, noError,
+               `{{template "foo" .}}`},
        // Errors.
        {"unclosed action", "hello{{range", hasError, ""},
        {"unmatched end", "{{end}}", hasError, ""},
@@ -277,6 +286,8 @@ var parseTests = []parseTest{
        {"wrong pipeline boolean", "{{.|true}}", hasError, ""},
        {"wrong pipeline nil", "{{'c'|nil}}", hasError, ""},
        {"empty pipeline", `{{printf "%d" ( ) }}`, hasError, ""},
+       // Missing pipeline in block
+       {"block definition", `{{block "foo"}}hello{{end}}`, hasError, ""},
 }
 
 var builtins = map[string]interface{}{
@@ -450,3 +461,26 @@ func TestErrors(t *testing.T) {
                }
        }
 }
+
+func TestBlock(t *testing.T) {
+       const (
+               input = `a{{block "inner" .}}bar{{.}}baz{{end}}b`
+               outer = `a{{template "inner" .}}b`
+               inner = `bar{{.}}baz`
+       )
+       treeSet := make(map[string]*Tree)
+       tmpl, err := New("outer").Parse(input, "", "", treeSet, nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+       if g, w := tmpl.Root.String(), outer; g != w {
+               t.Errorf("outer template = %q, want %q", g, w)
+       }
+       inTmpl := treeSet["inner"]
+       if inTmpl == nil {
+               t.Fatal("block did not define template")
+       }
+       if g, w := inTmpl.Root.String(), inner; g != w {
+               t.Errorf("inner template = %q, want %q", g, w)
+       }
+}
index 3e80982123af54136be2d705b2c6b75ebf71f45e..7a7f42a715371e8533787685e0a52e98735be10d 100644 (file)
@@ -5,7 +5,6 @@
 package template
 
 import (
-       "fmt"
        "reflect"
        "sync"
        "text/template/parse"
@@ -117,11 +116,10 @@ func (t *Template) copy(c *common) *Template {
 
 // AddParseTree adds parse tree for template with given name and associates it with t.
 // If the template does not already exist, it will create a new one.
-// It is an error to reuse a name except to overwrite an empty template.
+// If the template does exist, it will be replaced.
 func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
        t.init()
        // If the name is the name of this template, overwrite this template.
-       // The associate method checks it's not a redefinition.
        nt := t
        if name != t.name {
                nt = t.New(name)
@@ -162,8 +160,9 @@ func (t *Template) Delims(left, right string) *Template {
 
 // Funcs adds the elements of the argument map to the template's function map.
 // It panics if a value in the map is not a function with appropriate return
-// type. However, it is legal to overwrite elements of the map. The return
-// value is the template, so calls can be chained.
+// type or if the name cannot be used syntactically as a function in a template.
+// It is legal to overwrite elements of the map. The return value is the template,
+// so calls can be chained.
 func (t *Template) Funcs(funcMap FuncMap) *Template {
        t.init()
        t.muFuncs.Lock()
@@ -184,11 +183,7 @@ func (t *Template) Lookup(name string) *Template {
 
 // Parse defines the template by parsing the text. Nested template definitions will be
 // associated with the top-level template t. Parse may be called multiple times
-// to parse definitions of templates to associate with t. It is an error if a
-// resulting template is non-empty (contains content other than template
-// definitions) and would replace a non-empty template with the same name.
-// (In multiple calls to Parse with the same receiver template, only one call
-// can contain text other than space, comments, and template definitions.)
+// to parse definitions of templates to associate with t.
 func (t *Template) Parse(text string) (*Template, error) {
        t.init()
        t.muFuncs.RLock()
@@ -207,25 +202,17 @@ func (t *Template) Parse(text string) (*Template, error) {
 }
 
 // associate installs the new template into the group of templates associated
-// with t. It is an error to reuse a name except to overwrite an empty
-// template. The two are already known to share the common structure.
-// The boolean return value reports wither to store this tree as t.Tree.
+// with t. The two are already known to share the common structure.
+// The boolean return value reports whether to store this tree as t.Tree.
 func (t *Template) associate(new *Template, tree *parse.Tree) (bool, error) {
        if new.common != t.common {
                panic("internal error: associate not common")
        }
-       name := new.name
-       if old := t.tmpl[name]; old != nil {
-               oldIsEmpty := parse.IsEmptyTree(old.Root)
-               newIsEmpty := parse.IsEmptyTree(tree.Root)
-               if newIsEmpty {
-                       // Whether old is empty or not, new is empty; no reason to replace old.
-                       return false, nil
-               }
-               if !oldIsEmpty {
-                       return false, fmt.Errorf("template: redefinition of template %q", name)
-               }
+       if t.tmpl[new.name] != nil && parse.IsEmptyTree(tree.Root) {
+               // If a template by that name exists,
+               // don't replace it with an empty template.
+               return false, nil
        }
-       t.tmpl[name] = new
+       t.tmpl[new.name] = new
        return true, nil
 }
index 873d3ffde91d95a4282731ae7d87b9ccd4e0c0d7..e616feb048fba087248ae3180c8d7c8b99382314 100644 (file)
@@ -34,14 +34,23 @@ import "errors"
 // Numeric time zone offsets format as follows:
 //     -0700  ±hhmm
 //     -07:00 ±hh:mm
+//     -07    ±hh
 // Replacing the sign in the format with a Z triggers
 // the ISO 8601 behavior of printing Z instead of an
 // offset for the UTC zone.  Thus:
 //     Z0700  Z or ±hhmm
 //     Z07:00 Z or ±hh:mm
+//     Z07    Z or ±hh
 //
 // The executable example for time.Format demonstrates the working
 // of the layout string in detail and is a good reference.
+//
+// Note that the RFC822, RFC850, and RFC1123 formats should be applied
+// only to local times. Applying them to UTC times will use "UTC" as the
+// time zone abbreviation, while strictly speaking those RFCs require the
+// use of "GMT" in that case.
+// In general RFC1123Z should be used instead of RFC1123 for servers
+// that insist on that format, and RFC3339 should be preferred for new protocols.
 const (
        ANSIC       = "Mon Jan _2 15:04:05 2006"
        UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
@@ -86,6 +95,7 @@ const (
        stdTZ                    = iota                // "MST"
        stdISO8601TZ                                   // "Z0700"  // prints Z for UTC
        stdISO8601SecondsTZ                            // "Z070000"
+       stdISO8601ShortTZ                              // "Z07"
        stdISO8601ColonTZ                              // "Z07:00" // prints Z for UTC
        stdISO8601ColonSecondsTZ                       // "Z07:00:00"
        stdNumTZ                                       // "-0700"  // always numeric
@@ -162,8 +172,12 @@ func nextStdChunk(layout string) (prefix string, std int, suffix string) {
                        }
                        return layout[0:i], stdDay, layout[i+1:]
 
-               case '_': // _2
+               case '_': // _2, _2006
                        if len(layout) >= i+2 && layout[i+1] == '2' {
+                               //_2006 is really a literal _, followed by stdLongYear
+                               if len(layout) >= i+5 && layout[i+1:i+5] == "2006" {
+                                       return layout[0 : i+1], stdLongYear, layout[i+5:]
+                               }
                                return layout[0:i], stdUnderDay, layout[i+2:]
                        }
 
@@ -216,6 +230,9 @@ func nextStdChunk(layout string) (prefix string, std int, suffix string) {
                        if len(layout) >= i+6 && layout[i:i+6] == "Z07:00" {
                                return layout[0:i], stdISO8601ColonTZ, layout[i+6:]
                        }
+                       if len(layout) >= i+3 && layout[i:i+3] == "Z07" {
+                               return layout[0:i], stdISO8601ShortTZ, layout[i+3:]
+                       }
 
                case '.': // .000 or .999 - repeated digits for fractional seconds.
                        if i+1 < len(layout) && (layout[i+1] == '0' || layout[i+1] == '9') {
@@ -518,7 +535,7 @@ func (t Time) AppendFormat(b []byte, layout string) []byte {
                case stdZeroMinute:
                        b = appendInt(b, min, 2)
                case stdSecond:
-                       b = appendInt(b, sec, 2)
+                       b = appendInt(b, sec, 0)
                case stdZeroSecond:
                        b = appendInt(b, sec, 2)
                case stdPM:
@@ -533,10 +550,10 @@ func (t Time) AppendFormat(b []byte, layout string) []byte {
                        } else {
                                b = append(b, "am"...)
                        }
-               case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ:
+               case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumColonTZ, stdNumSecondsTz, stdNumShortTZ, stdNumColonSecondsTZ:
                        // Ugly special case.  We cheat and take the "Z" variants
                        // to mean "the time zone as formatted for ISO 8601".
-                       if offset == 0 && (std == stdISO8601TZ || std == stdISO8601ColonTZ || std == stdISO8601SecondsTZ || std == stdISO8601ColonSecondsTZ) {
+                       if offset == 0 && (std == stdISO8601TZ || std == stdISO8601ColonTZ || std == stdISO8601SecondsTZ || std == stdISO8601ShortTZ || std == stdISO8601ColonSecondsTZ) {
                                b = append(b, 'Z')
                                break
                        }
@@ -553,7 +570,9 @@ func (t Time) AppendFormat(b []byte, layout string) []byte {
                        if std == stdISO8601ColonTZ || std == stdNumColonTZ || std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ {
                                b = append(b, ':')
                        }
-                       b = appendInt(b, zone%60, 2)
+                       if std != stdNumShortTZ && std != stdISO8601ShortTZ {
+                               b = appendInt(b, zone%60, 2)
+                       }
 
                        // append seconds if appropriate
                        if std == stdISO8601SecondsTZ || std == stdNumSecondsTz || std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ {
@@ -696,6 +715,11 @@ func skip(value, prefix string) (string, error) {
 // location and zone in the returned time. Otherwise it records the time as
 // being in a fabricated location with time fixed at the given zone offset.
 //
+// No checking is done that the day of the month is within the month's
+// valid dates; any one- or two-digit value is accepted. For example
+// February 31 and even February 99 are valid dates, specifying dates
+// in March and May. This behavior is consistent with time.Date.
+//
 // When parsing a time with a zone abbreviation like MST, if the zone abbreviation
 // has a defined offset in the current location, then that offset is used.
 // The zone abbreviation "UTC" is recognized as UTC regardless of location.
@@ -794,7 +818,8 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
                                value = value[1:]
                        }
                        day, value, err = getnum(value, std == stdZeroDay)
-                       if day < 0 || 31 < day {
+                       if day < 0 {
+                               // Note that we allow any one- or two-digit day here.
                                rangeErrString = "day"
                        }
                case stdHour:
@@ -861,8 +886,8 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
                        default:
                                err = errBad
                        }
-               case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ:
-                       if (std == stdISO8601TZ || std == stdISO8601ColonTZ) && len(value) >= 1 && value[0] == 'Z' {
+               case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ:
+                       if (std == stdISO8601TZ || std == stdISO8601ShortTZ || std == stdISO8601ColonTZ) && len(value) >= 1 && value[0] == 'Z' {
                                value = value[1:]
                                z = UTC
                                break
@@ -878,7 +903,7 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
                                        break
                                }
                                sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], "00", value[6:]
-                       } else if std == stdNumShortTZ {
+                       } else if std == stdNumShortTZ || std == stdISO8601ShortTZ {
                                if len(value) < 3 {
                                        err = errBad
                                        break
@@ -975,6 +1000,11 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
                hour = 0
        }
 
+       // Validate the day of the month.
+       if day > daysIn(Month(month), year) {
+               return Time{}, &ParseError{alayout, avalue, "", value, ": day out of range"}
+       }
+
        if z != nil {
                return Date(year, Month(month), day, hour, min, sec, nsec, z), nil
        }
index 75a08c74534e898c48d17fa071ef4a072a3cde41..a2592e2ceb56068d8bded0940a534f41779341f8 100644 (file)
@@ -74,6 +74,16 @@ func TestFormat(t *testing.T) {
        }
 }
 
+// issue 12440.
+func TestFormatSingleDigits(t *testing.T) {
+       time := Date(2001, 2, 3, 4, 5, 6, 700000000, UTC)
+       test := FormatTest{"single digit format", "3:4:5", "4:5:6"}
+       result := time.Format(test.format)
+       if result != test.result {
+               t.Errorf("%s expected %q got %q", test.name, test.result, result)
+       }
+}
+
 func TestFormatShortYear(t *testing.T) {
        years := []int{
                -100001, -100000, -99999,
@@ -183,6 +193,57 @@ func TestParse(t *testing.T) {
        }
 }
 
+// All parsed with ANSIC.
+var dayOutOfRangeTests = []struct {
+       date string
+       ok   bool
+}{
+       {"Thu Jan 99 21:00:57 2010", false},
+       {"Thu Jan 31 21:00:57 2010", true},
+       {"Thu Jan 32 21:00:57 2010", false},
+       {"Thu Feb 28 21:00:57 2012", true},
+       {"Thu Feb 29 21:00:57 2012", true},
+       {"Thu Feb 29 21:00:57 2010", false},
+       {"Thu Mar 31 21:00:57 2010", true},
+       {"Thu Mar 32 21:00:57 2010", false},
+       {"Thu Apr 30 21:00:57 2010", true},
+       {"Thu Apr 31 21:00:57 2010", false},
+       {"Thu May 31 21:00:57 2010", true},
+       {"Thu May 32 21:00:57 2010", false},
+       {"Thu Jun 30 21:00:57 2010", true},
+       {"Thu Jun 31 21:00:57 2010", false},
+       {"Thu Jul 31 21:00:57 2010", true},
+       {"Thu Jul 32 21:00:57 2010", false},
+       {"Thu Aug 31 21:00:57 2010", true},
+       {"Thu Aug 32 21:00:57 2010", false},
+       {"Thu Sep 30 21:00:57 2010", true},
+       {"Thu Sep 31 21:00:57 2010", false},
+       {"Thu Oct 31 21:00:57 2010", true},
+       {"Thu Oct 32 21:00:57 2010", false},
+       {"Thu Nov 30 21:00:57 2010", true},
+       {"Thu Nov 31 21:00:57 2010", false},
+       {"Thu Dec 31 21:00:57 2010", true},
+       {"Thu Dec 32 21:00:57 2010", false},
+}
+
+func TestParseDayOutOfRange(t *testing.T) {
+       for _, test := range dayOutOfRangeTests {
+               _, err := Parse(ANSIC, test.date)
+               switch {
+               case test.ok && err == nil:
+                       // OK
+               case !test.ok && err != nil:
+                       if !strings.Contains(err.Error(), "day out of range") {
+                               t.Errorf("%q: expected 'day' error, got %v", test.date, err)
+                       }
+               case test.ok && err != nil:
+                       t.Errorf("%q: unexpected error: %v", test.date, err)
+               case !test.ok && err == nil:
+                       t.Errorf("%q: expected 'day' error, got none", test.date)
+               }
+       }
+}
+
 func TestParseInLocation(t *testing.T) {
        // Check that Parse (and ParseInLocation) understand that
        // Feb 01 AST (Arabia Standard Time) and Feb 01 AST (Atlantic Standard Time)
@@ -493,6 +554,9 @@ var secondsTimeZoneOffsetTests = []SecondsTimeZoneOffsetTest{
        {"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
        {"2006-01-02T15:04:05Z070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
        {"2006-01-02T15:04:05Z07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
+       {"2006-01-02T15:04:05-07", "1871-01-01T05:33:02+01", 1 * 60 * 60},
+       {"2006-01-02T15:04:05-07", "1871-01-01T05:33:02-02", -2 * 60 * 60},
+       {"2006-01-02T15:04:05Z07", "1871-01-01T05:33:02-02", -2 * 60 * 60},
 }
 
 func TestParseSecondsInTimeZone(t *testing.T) {
@@ -518,3 +582,22 @@ func TestFormatSecondsInTimeZone(t *testing.T) {
                }
        }
 }
+
+// Issue 11334.
+func TestUnderscoreTwoThousand(t *testing.T) {
+       format := "15:04_20060102"
+       input := "14:38_20150618"
+       time, err := Parse(format, input)
+       if err != nil {
+               t.Error(err)
+       }
+       if y, m, d := time.Date(); y != 2015 || m != 6 || d != 18 {
+               t.Errorf("Incorrect y/m/d, got %d/%d/%d", y, m, d)
+       }
+       if h := time.Hour(); h != 14 {
+               t.Errorf("Incorrect hour, got %d", h)
+       }
+       if m := time.Minute(); m != 38 {
+               t.Errorf("Incorrect minute, got %d", m)
+       }
+}
index 294cc77f417e62986f4c004efc4327cb8f98b4be..ef4ba5842de9027002d5df8962c7169146483336 100644 (file)
@@ -180,7 +180,7 @@ func (d Weekday) String() string { return days[d] }
 // everywhere.
 //
 // The calendar runs on an exact 400 year cycle: a 400-year calendar
-// printed for 1970-2469 will apply as well to 2470-2869.  Even the days
+// printed for 1970-2469 will apply as well to 2370-2769.  Even the days
 // of the week match up.  It simplifies the computations to choose the
 // cycle boundaries so that the exceptional years are always delayed as
 // long as possible.  That means choosing a year equal to 1 mod 400, so
@@ -935,7 +935,12 @@ func (t Time) MarshalJSON() ([]byte, error) {
                // 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
+
+       b := make([]byte, 0, len(RFC3339Nano)+2)
+       b = append(b, '"')
+       b = t.AppendFormat(b, RFC3339Nano)
+       b = append(b, '"')
+       return b, nil
 }
 
 // UnmarshalJSON implements the json.Unmarshaler interface.
@@ -952,7 +957,9 @@ func (t Time) MarshalText() ([]byte, error) {
        if y := t.Year(); y < 0 || y >= 10000 {
                return nil, errors.New("Time.MarshalText: year outside of range [0,9999]")
        }
-       return []byte(t.Format(RFC3339Nano)), nil
+
+       b := make([]byte, 0, len(RFC3339Nano))
+       return t.AppendFormat(b, RFC3339Nano), nil
 }
 
 // UnmarshalText implements the encoding.TextUnmarshaler interface.
index 2d16ea59ae3a9230a60b13d68b71d833c539ecd1..a925e98a838e2981e40d7ec3a8affc3b437c3c73 100644 (file)
@@ -1060,6 +1060,20 @@ func BenchmarkFormatNow(b *testing.B) {
        }
 }
 
+func BenchmarkMarshalJSON(b *testing.B) {
+       t := Now()
+       for i := 0; i < b.N; i++ {
+               t.MarshalJSON()
+       }
+}
+
+func BenchmarkMarshalText(b *testing.B) {
+       t := Now()
+       for i := 0; i < b.N; i++ {
+               t.MarshalText()
+       }
+}
+
 func BenchmarkParse(b *testing.B) {
        for i := 0; i < b.N; i++ {
                Parse(ANSIC, "Mon Jan  2 15:04:05 2006")
index c8e53a27cf02328ffc8a16909e95dcbea219765d..c56743933f92d0ff62e0d7d1b98c9b71c5f91c4e 100644 (file)
@@ -21,7 +21,7 @@ type Location struct {
        // To avoid the binary search through tx, keep a
        // static one-element cache that gives the correct
        // zone for the time when the Location was created.
-       // if cacheStart <= t <= cacheEnd,
+       // if cacheStart <= t < cacheEnd,
        // lookup can return cacheZone.
        // The units for cacheStart and cacheEnd are seconds
        // since January 1, 1970 UTC, to match the argument
index d04ebec614ef75cb602568635d749ef433842d84..bcb8ccd56326264979fc7a7ab251bfcf8d8a1383 100644 (file)
@@ -20,8 +20,9 @@ import (
 // The implementation assumes that this year's rules for daylight savings
 // time apply to all previous and future years as well.
 
-// matchZoneKey checks if stdname and dstname match the corresponding "Std"
-// and "Dlt" key values in the kname key stored under the open registry key zones.
+// matchZoneKey checks if stdname and dstname match the corresponding key
+// values "MUI_Std" and MUI_Dlt" or "Std" and "Dlt" (the latter down-level
+// from Vista) in the kname key stored under the open registry key zones.
 func matchZoneKey(zones registry.Key, kname string, stdname, dstname string) (matched bool, err2 error) {
        k, err := registry.OpenKey(zones, kname, registry.READ)
        if err != nil {
@@ -29,18 +30,27 @@ func matchZoneKey(zones registry.Key, kname string, stdname, dstname string) (ma
        }
        defer k.Close()
 
-       s, _, err := k.GetStringValue("Std")
-       if err != nil {
-               return false, err
+       var std, dlt string
+       if err = registry.LoadRegLoadMUIString(); err == nil {
+               // Try MUI_Std and MUI_Dlt first, fallback to Std and Dlt if *any* error occurs
+               std, err = k.GetMUIStringValue("MUI_Std")
+               if err == nil {
+                       dlt, err = k.GetMUIStringValue("MUI_Dlt")
+               }
        }
-       if s != stdname {
-               return false, nil
+       if err != nil { // Fallback to Std and Dlt
+               if std, _, err = k.GetStringValue("Std"); err != nil {
+                       return false, err
+               }
+               if dlt, _, err = k.GetStringValue("Dlt"); err != nil {
+                       return false, err
+               }
        }
-       s, _, err = k.GetStringValue("Dlt")
-       if err != nil {
-               return false, err
+
+       if std != stdname {
+               return false, nil
        }
-       if s != dstname && dstname != stdname {
+       if dlt != dstname && dstname != stdname {
                return false, nil
        }
        return true, nil
diff --git a/libgo/go/unicode/example_test.go b/libgo/go/unicode/example_test.go
new file mode 100644 (file)
index 0000000..50c5b18
--- /dev/null
@@ -0,0 +1,196 @@
+// Copyright 2015 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 unicode_test
+
+import (
+       "fmt"
+       "unicode"
+)
+
+// Functions starting with "Is" can be used to inspect which table of range a
+// rune belongs to. Note that runes may fit into more than one range.
+func Example_is() {
+
+       // constant with mixed type runes
+       const mixed = "\b5Ὂg̀9! ℃ᾭG"
+       for _, c := range mixed {
+               fmt.Printf("For %q:\n", c)
+               if unicode.IsControl(c) {
+                       fmt.Println("\tis control rune")
+               }
+               if unicode.IsDigit(c) {
+                       fmt.Println("\tis digit rune")
+               }
+               if unicode.IsGraphic(c) {
+                       fmt.Println("\tis graphic rune")
+               }
+               if unicode.IsLetter(c) {
+                       fmt.Println("\tis letter rune")
+               }
+               if unicode.IsLower(c) {
+                       fmt.Println("\tis lower case rune")
+               }
+               if unicode.IsMark(c) {
+                       fmt.Println("\tis mark rune")
+               }
+               if unicode.IsNumber(c) {
+                       fmt.Println("\tis number rune")
+               }
+               if unicode.IsPrint(c) {
+                       fmt.Println("\tis printable rune")
+               }
+               if !unicode.IsPrint(c) {
+                       fmt.Println("\tis not printable rune")
+               }
+               if unicode.IsPunct(c) {
+                       fmt.Println("\tis punct rune")
+               }
+               if unicode.IsSpace(c) {
+                       fmt.Println("\tis space rune")
+               }
+               if unicode.IsSymbol(c) {
+                       fmt.Println("\tis symbol rune")
+               }
+               if unicode.IsTitle(c) {
+                       fmt.Println("\tis title case rune")
+               }
+               if unicode.IsUpper(c) {
+                       fmt.Println("\tis upper case rune")
+               }
+       }
+
+       // Output:
+       // For '\b':
+       //      is control rune
+       //      is not printable rune
+       // For '5':
+       //      is digit rune
+       //      is graphic rune
+       //      is number rune
+       //      is printable rune
+       // For 'Ὂ':
+       //      is graphic rune
+       //      is letter rune
+       //      is printable rune
+       //      is upper case rune
+       // For 'g':
+       //      is graphic rune
+       //      is letter rune
+       //      is lower case rune
+       //      is printable rune
+       // For '̀':
+       //      is graphic rune
+       //      is mark rune
+       //      is printable rune
+       // For '9':
+       //      is digit rune
+       //      is graphic rune
+       //      is number rune
+       //      is printable rune
+       // For '!':
+       //      is graphic rune
+       //      is printable rune
+       //      is punct rune
+       // For ' ':
+       //      is graphic rune
+       //      is printable rune
+       //      is space rune
+       // For '℃':
+       //      is graphic rune
+       //      is printable rune
+       //      is symbol rune
+       // For 'ᾭ':
+       //      is graphic rune
+       //      is letter rune
+       //      is printable rune
+       //      is title case rune
+       // For 'G':
+       //      is graphic rune
+       //      is letter rune
+       //      is printable rune
+       //      is upper case rune
+}
+
+func ExampleSimpleFold() {
+       fmt.Printf("%#U\n", unicode.SimpleFold('A'))      // 'a'
+       fmt.Printf("%#U\n", unicode.SimpleFold('a'))      // 'A'
+       fmt.Printf("%#U\n", unicode.SimpleFold('K'))      // 'k'
+       fmt.Printf("%#U\n", unicode.SimpleFold('k'))      // '\u212A' (Kelvin symbol, K)
+       fmt.Printf("%#U\n", unicode.SimpleFold('\u212A')) // 'K'
+       fmt.Printf("%#U\n", unicode.SimpleFold('1'))      // '1'
+
+       // Output:
+       // U+0061 'a'
+       // U+0041 'A'
+       // U+006B 'k'
+       // U+212A 'K'
+       // U+004B 'K'
+       // U+0031 '1'
+}
+
+func ExampleTo() {
+       const lcG = 'g'
+       fmt.Printf("%#U\n", unicode.To(unicode.UpperCase, lcG))
+       fmt.Printf("%#U\n", unicode.To(unicode.LowerCase, lcG))
+       fmt.Printf("%#U\n", unicode.To(unicode.TitleCase, lcG))
+
+       const ucG = 'G'
+       fmt.Printf("%#U\n", unicode.To(unicode.UpperCase, ucG))
+       fmt.Printf("%#U\n", unicode.To(unicode.LowerCase, ucG))
+       fmt.Printf("%#U\n", unicode.To(unicode.TitleCase, ucG))
+
+       // Output:
+       // U+0047 'G'
+       // U+0067 'g'
+       // U+0047 'G'
+       // U+0047 'G'
+       // U+0067 'g'
+       // U+0047 'G'
+}
+
+func ExampleToLower() {
+       const ucG = 'G'
+       fmt.Printf("%#U\n", unicode.ToLower(ucG))
+
+       // Output:
+       // U+0067 'g'
+}
+func ExampleToTitle() {
+       const ucG = 'g'
+       fmt.Printf("%#U\n", unicode.ToTitle(ucG))
+
+       // Output:
+       // U+0047 'G'
+}
+
+func ExampleToUpper() {
+       const ucG = 'g'
+       fmt.Printf("%#U\n", unicode.ToUpper(ucG))
+
+       // Output:
+       // U+0047 'G'
+}
+
+func ExampleSpecialCase() {
+       t := unicode.TurkishCase
+
+       const lci = 'i'
+       fmt.Printf("%#U\n", t.ToLower(lci))
+       fmt.Printf("%#U\n", t.ToTitle(lci))
+       fmt.Printf("%#U\n", t.ToUpper(lci))
+
+       const uci = 'İ'
+       fmt.Printf("%#U\n", t.ToLower(uci))
+       fmt.Printf("%#U\n", t.ToTitle(uci))
+       fmt.Printf("%#U\n", t.ToUpper(uci))
+
+       // Output:
+       // U+0069 'i'
+       // U+0130 'İ'
+       // U+0130 'İ'
+       // U+0069 'i'
+       // U+0130 'İ'
+       // U+0130 'İ'
+}
index 370a9d1174d7bdedace49bdb05370b21101f09d2..8bb42062f9ed8f6007c43286f20de16563b988da 100644 (file)
@@ -53,7 +53,7 @@ var Categories = map[string]*RangeTable{
 
 var _C = &RangeTable{
        R16: []Range16{
-               {0x0001, 0x001f, 1},
+               {0x0000, 0x001f, 1},
                {0x007f, 0x009f, 1},
                {0x00ad, 0x0600, 1363},
                {0x0601, 0x0605, 1},
@@ -81,7 +81,7 @@ var _C = &RangeTable{
 
 var _Cc = &RangeTable{
        R16: []Range16{
-               {0x0001, 0x001f, 1},
+               {0x0000, 0x001f, 1},
                {0x007f, 0x009f, 1},
        },
        LatinOffset: 2,
index 9ac37184d69aa4fd308db2280cfc1b343a779c7f..bbaf14aab8ff66eeae190193271630a36a6fcb82 100644 (file)
@@ -40,206 +40,208 @@ const (
        rune1Max = 1<<7 - 1
        rune2Max = 1<<11 - 1
        rune3Max = 1<<16 - 1
-)
-
-func decodeRuneInternal(p []byte) (r rune, size int, short bool) {
-       n := len(p)
-       if n < 1 {
-               return RuneError, 0, true
-       }
-       c0 := p[0]
-
-       // 1-byte, 7-bit sequence?
-       if c0 < tx {
-               return rune(c0), 1, false
-       }
-
-       // unexpected continuation byte?
-       if c0 < t2 {
-               return RuneError, 1, false
-       }
-
-       // need first continuation byte
-       if n < 2 {
-               return RuneError, 1, true
-       }
-       c1 := p[1]
-       if c1 < tx || t2 <= c1 {
-               return RuneError, 1, false
-       }
-
-       // 2-byte, 11-bit sequence?
-       if c0 < t3 {
-               r = rune(c0&mask2)<<6 | rune(c1&maskx)
-               if r <= rune1Max {
-                       return RuneError, 1, false
-               }
-               return r, 2, false
-       }
 
-       // need second continuation byte
-       if n < 3 {
-               return RuneError, 1, true
-       }
-       c2 := p[2]
-       if c2 < tx || t2 <= c2 {
-               return RuneError, 1, false
-       }
-
-       // 3-byte, 16-bit sequence?
-       if c0 < t4 {
-               r = rune(c0&mask3)<<12 | rune(c1&maskx)<<6 | rune(c2&maskx)
-               if r <= rune2Max {
-                       return RuneError, 1, false
-               }
-               if surrogateMin <= r && r <= surrogateMax {
-                       return RuneError, 1, false
-               }
-               return r, 3, false
-       }
-
-       // need third continuation byte
-       if n < 4 {
-               return RuneError, 1, true
-       }
-       c3 := p[3]
-       if c3 < tx || t2 <= c3 {
-               return RuneError, 1, false
-       }
-
-       // 4-byte, 21-bit sequence?
-       if c0 < t5 {
-               r = rune(c0&mask4)<<18 | rune(c1&maskx)<<12 | rune(c2&maskx)<<6 | rune(c3&maskx)
-               if r <= rune3Max || MaxRune < r {
-                       return RuneError, 1, false
-               }
-               return r, 4, false
-       }
+       // The default lowest and highest continuation byte.
+       locb = 0x80 // 1000 0000
+       hicb = 0xBF // 1011 1111
+
+       // These names of these constants are chosen to give nice alignment in the
+       // table below. The first nibble is an index into acceptRanges or F for
+       // special one-byte cases. The second nibble is the Rune length or the
+       // Status for the special one-byte case.
+       xx = 0xF1 // invalid: size 1
+       as = 0xF0 // ASCII: size 1
+       s1 = 0x02 // accept 0, size 2
+       s2 = 0x13 // accept 1, size 3
+       s3 = 0x03 // accept 0, size 3
+       s4 = 0x23 // accept 2, size 3
+       s5 = 0x34 // accept 3, size 4
+       s6 = 0x04 // accept 0, size 4
+       s7 = 0x44 // accept 4, size 4
+)
 
-       // error
-       return RuneError, 1, false
+// first is information about the first byte in a UTF-8 sequence.
+var first = [256]uint8{
+       //   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+       as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x00-0x0F
+       as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x10-0x1F
+       as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x20-0x2F
+       as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x30-0x3F
+       as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x40-0x4F
+       as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x50-0x5F
+       as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x60-0x6F
+       as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x70-0x7F
+       //   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+       xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x80-0x8F
+       xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x90-0x9F
+       xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xA0-0xAF
+       xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xB0-0xBF
+       xx, xx, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xC0-0xCF
+       s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xD0-0xDF
+       s2, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s4, s3, s3, // 0xE0-0xEF
+       s5, s6, s6, s6, s7, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xF0-0xFF
 }
 
-func decodeRuneInStringInternal(s string) (r rune, size int, short bool) {
-       n := len(s)
-       if n < 1 {
-               return RuneError, 0, true
-       }
-       c0 := s[0]
-
-       // 1-byte, 7-bit sequence?
-       if c0 < tx {
-               return rune(c0), 1, false
-       }
-
-       // unexpected continuation byte?
-       if c0 < t2 {
-               return RuneError, 1, false
-       }
-
-       // need first continuation byte
-       if n < 2 {
-               return RuneError, 1, true
-       }
-       c1 := s[1]
-       if c1 < tx || t2 <= c1 {
-               return RuneError, 1, false
-       }
-
-       // 2-byte, 11-bit sequence?
-       if c0 < t3 {
-               r = rune(c0&mask2)<<6 | rune(c1&maskx)
-               if r <= rune1Max {
-                       return RuneError, 1, false
-               }
-               return r, 2, false
-       }
-
-       // need second continuation byte
-       if n < 3 {
-               return RuneError, 1, true
-       }
-       c2 := s[2]
-       if c2 < tx || t2 <= c2 {
-               return RuneError, 1, false
-       }
-
-       // 3-byte, 16-bit sequence?
-       if c0 < t4 {
-               r = rune(c0&mask3)<<12 | rune(c1&maskx)<<6 | rune(c2&maskx)
-               if r <= rune2Max {
-                       return RuneError, 1, false
-               }
-               if surrogateMin <= r && r <= surrogateMax {
-                       return RuneError, 1, false
-               }
-               return r, 3, false
-       }
-
-       // need third continuation byte
-       if n < 4 {
-               return RuneError, 1, true
-       }
-       c3 := s[3]
-       if c3 < tx || t2 <= c3 {
-               return RuneError, 1, false
-       }
-
-       // 4-byte, 21-bit sequence?
-       if c0 < t5 {
-               r = rune(c0&mask4)<<18 | rune(c1&maskx)<<12 | rune(c2&maskx)<<6 | rune(c3&maskx)
-               if r <= rune3Max || MaxRune < r {
-                       return RuneError, 1, false
-               }
-               return r, 4, false
-       }
+// acceptRange gives the range of valid values for the second byte in a UTF-8
+// sequence.
+type acceptRange struct {
+       lo uint8 // lowest value for second byte.
+       hi uint8 // highest value for second byte.
+}
 
-       // error
-       return RuneError, 1, false
+var acceptRanges = [...]acceptRange{
+       0: {locb, hicb},
+       1: {0xA0, hicb},
+       2: {locb, 0x9F},
+       3: {0x90, hicb},
+       4: {locb, 0x8F},
 }
 
 // FullRune reports whether the bytes in p begin with a full UTF-8 encoding of a rune.
 // An invalid encoding is considered a full Rune since it will convert as a width-1 error rune.
 func FullRune(p []byte) bool {
-       _, _, short := decodeRuneInternal(p)
-       return !short
+       n := len(p)
+       if n == 0 {
+               return false
+       }
+       x := first[p[0]]
+       if n >= int(x&7) {
+               return true // ASCII, invalid or valid.
+       }
+       // Must be short or invalid.
+       accept := acceptRanges[x>>4]
+       if n > 1 {
+               if c := p[1]; c < accept.lo || accept.hi < c {
+                       return true
+               } else if n > 2 && (p[2] < locb || hicb < p[2]) {
+                       return true
+               }
+       }
+       return false
 }
 
 // FullRuneInString is like FullRune but its input is a string.
 func FullRuneInString(s string) bool {
-       _, _, short := decodeRuneInStringInternal(s)
-       return !short
+       n := len(s)
+       if n == 0 {
+               return false
+       }
+       x := first[s[0]]
+       if n >= int(x&7) {
+               return true // ASCII, invalid, or valid.
+       }
+       // Must be short or invalid.
+       accept := acceptRanges[x>>4]
+       if n > 1 {
+               if c := s[1]; c < accept.lo || accept.hi < c {
+                       return true
+               } else if n > 2 && (s[2] < locb || hicb < s[2]) {
+                       return true
+               }
+       }
+       return false
 }
 
 // DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and
 // its width in bytes. If p is empty it returns (RuneError, 0). Otherwise, if
 // the encoding is invalid, it returns (RuneError, 1). Both are impossible
-// results for correct UTF-8.
+// results for correct, non-empty UTF-8.
 //
 // An encoding is invalid if it is incorrect UTF-8, encodes a rune that is
 // out of range, or is not the shortest possible UTF-8 encoding for the
 // value. No other validation is performed.
 func DecodeRune(p []byte) (r rune, size int) {
-       r, size, _ = decodeRuneInternal(p)
-       return
+       n := len(p)
+       if n < 1 {
+               return RuneError, 0
+       }
+       p0 := p[0]
+       x := first[p0]
+       if x >= as {
+               // The following code simulates an additional check for x == xx and
+               // handling the ASCII and invalid cases accordingly. This mask-and-or
+               // approach prevents an additional branch.
+               mask := rune(x) << 31 >> 31 // Create 0x0000 or 0xFFFF.
+               return rune(p[0])&^mask | RuneError&mask, 1
+       }
+       sz := x & 7
+       accept := acceptRanges[x>>4]
+       if n < int(sz) {
+               return RuneError, 1
+       }
+       b1 := p[1]
+       if b1 < accept.lo || accept.hi < b1 {
+               return RuneError, 1
+       }
+       if sz == 2 {
+               return rune(p0&mask2)<<6 | rune(b1&maskx), 2
+       }
+       b2 := p[2]
+       if b2 < locb || hicb < b2 {
+               return RuneError, 1
+       }
+       if sz == 3 {
+               return rune(p0&mask3)<<12 | rune(b1&maskx)<<6 | rune(b2&maskx), 3
+       }
+       b3 := p[3]
+       if b3 < locb || hicb < b3 {
+               return RuneError, 1
+       }
+       return rune(p0&mask4)<<18 | rune(b1&maskx)<<12 | rune(b2&maskx)<<6 | rune(b3&maskx), 4
 }
 
 // DecodeRuneInString is like DecodeRune but its input is a string. If s is
 // empty it returns (RuneError, 0). Otherwise, if the encoding is invalid, it
-// returns (RuneError, 1). Both are impossible results for correct UTF-8.
+// returns (RuneError, 1). Both are impossible results for correct, non-empty
+// UTF-8.
 //
 // An encoding is invalid if it is incorrect UTF-8, encodes a rune that is
 // out of range, or is not the shortest possible UTF-8 encoding for the
 // value. No other validation is performed.
 func DecodeRuneInString(s string) (r rune, size int) {
-       r, size, _ = decodeRuneInStringInternal(s)
-       return
+       n := len(s)
+       if n < 1 {
+               return RuneError, 0
+       }
+       s0 := s[0]
+       x := first[s0]
+       if x >= as {
+               // The following code simulates an additional check for x == xx and
+               // handling the ASCII and invalid cases accordingly. This mask-and-or
+               // approach prevents an additional branch.
+               mask := rune(x) << 31 >> 31 // Create 0x0000 or 0xFFFF.
+               return rune(s[0])&^mask | RuneError&mask, 1
+       }
+       sz := x & 7
+       accept := acceptRanges[x>>4]
+       if n < int(sz) {
+               return RuneError, 1
+       }
+       s1 := s[1]
+       if s1 < accept.lo || accept.hi < s1 {
+               return RuneError, 1
+       }
+       if sz == 2 {
+               return rune(s0&mask2)<<6 | rune(s1&maskx), 2
+       }
+       s2 := s[2]
+       if s2 < locb || hicb < s2 {
+               return RuneError, 1
+       }
+       if sz == 3 {
+               return rune(s0&mask3)<<12 | rune(s1&maskx)<<6 | rune(s2&maskx), 3
+       }
+       s3 := s[3]
+       if s3 < locb || hicb < s3 {
+               return RuneError, 1
+       }
+       return rune(s0&mask4)<<18 | rune(s1&maskx)<<12 | rune(s2&maskx)<<6 | rune(s3&maskx), 4
 }
 
 // DecodeLastRune unpacks the last UTF-8 encoding in p and returns the rune and
 // its width in bytes. If p is empty it returns (RuneError, 0). Otherwise, if
 // the encoding is invalid, it returns (RuneError, 1). Both are impossible
-// results for correct UTF-8.
+// results for correct, non-empty UTF-8.
 //
 // An encoding is invalid if it is incorrect UTF-8, encodes a rune that is
 // out of range, or is not the shortest possible UTF-8 encoding for the
@@ -278,7 +280,8 @@ func DecodeLastRune(p []byte) (r rune, size int) {
 
 // DecodeLastRuneInString is like DecodeLastRune but its input is a string. If
 // s is empty it returns (RuneError, 0). Otherwise, if the encoding is invalid,
-// it returns (RuneError, 1). Both are impossible results for correct UTF-8.
+// it returns (RuneError, 1). Both are impossible results for correct,
+// non-empty UTF-8.
 //
 // An encoding is invalid if it is incorrect UTF-8, encodes a rune that is
 // out of range, or is not the shortest possible UTF-8 encoding for the
@@ -367,65 +370,141 @@ func EncodeRune(p []byte, r rune) int {
 // RuneCount returns the number of runes in p.  Erroneous and short
 // encodings are treated as single runes of width 1 byte.
 func RuneCount(p []byte) int {
-       i := 0
+       np := len(p)
        var n int
-       for n = 0; i < len(p); n++ {
-               if p[i] < RuneSelf {
+       for i := 0; i < np; {
+               n++
+               c := p[i]
+               if c < RuneSelf {
+                       // ASCII fast path
                        i++
-               } else {
-                       _, size := DecodeRune(p[i:])
-                       i += size
+                       continue
+               }
+               x := first[c]
+               if x == xx {
+                       i++ // invalid.
+                       continue
+               }
+               size := int(x & 7)
+               if i+size > np {
+                       i++ // Short or invalid.
+                       continue
                }
+               accept := acceptRanges[x>>4]
+               if c := p[i+1]; c < accept.lo || accept.hi < c {
+                       size = 1
+               } else if size == 2 {
+               } else if c := p[i+2]; c < locb || hicb < c {
+                       size = 1
+               } else if size == 3 {
+               } else if c := p[i+3]; c < locb || hicb < c {
+                       size = 1
+               }
+               i += size
        }
        return n
 }
 
 // RuneCountInString is like RuneCount but its input is a string.
 func RuneCountInString(s string) (n int) {
-       for range s {
-               n++
+       ns := len(s)
+       for i := 0; i < ns; n++ {
+               c := s[i]
+               if c < RuneSelf {
+                       // ASCII fast path
+                       i++
+                       continue
+               }
+               x := first[c]
+               if x == xx {
+                       i++ // invalid.
+                       continue
+               }
+               size := int(x & 7)
+               if i+size > ns {
+                       i++ // Short or invalid.
+                       continue
+               }
+               accept := acceptRanges[x>>4]
+               if c := s[i+1]; c < accept.lo || accept.hi < c {
+                       size = 1
+               } else if size == 2 {
+               } else if c := s[i+2]; c < locb || hicb < c {
+                       size = 1
+               } else if size == 3 {
+               } else if c := s[i+3]; c < locb || hicb < c {
+                       size = 1
+               }
+               i += size
        }
-       return
+       return n
 }
 
-// RuneStart reports whether the byte could be the first byte of
-// an encoded rune.  Second and subsequent bytes always have the top
-// two bits set to 10.
+// RuneStart reports whether the byte could be the first byte of an encoded,
+// possibly invalid rune.  Second and subsequent bytes always have the top two
+// bits set to 10.
 func RuneStart(b byte) bool { return b&0xC0 != 0x80 }
 
 // Valid reports whether p consists entirely of valid UTF-8-encoded runes.
 func Valid(p []byte) bool {
-       i := 0
-       for i < len(p) {
-               if p[i] < RuneSelf {
+       n := len(p)
+       for i := 0; i < n; {
+               pi := p[i]
+               if pi < RuneSelf {
                        i++
-               } else {
-                       _, size := DecodeRune(p[i:])
-                       if size == 1 {
-                               // All valid runes of size 1 (those
-                               // below RuneSelf) were handled above.
-                               // This must be a RuneError.
-                               return false
-                       }
-                       i += size
+                       continue
+               }
+               x := first[pi]
+               if x == xx {
+                       return false // Illegal starter byte.
                }
+               size := int(x & 7)
+               if i+size > n {
+                       return false // Short or invalid.
+               }
+               accept := acceptRanges[x>>4]
+               if c := p[i+1]; c < accept.lo || accept.hi < c {
+                       return false
+               } else if size == 2 {
+               } else if c := p[i+2]; c < locb || hicb < c {
+                       return false
+               } else if size == 3 {
+               } else if c := p[i+3]; c < locb || hicb < c {
+                       return false
+               }
+               i += size
        }
        return true
 }
 
 // ValidString reports whether s consists entirely of valid UTF-8-encoded runes.
 func ValidString(s string) bool {
-       for i, r := range s {
-               if r == RuneError {
-                       // The RuneError value can be an error
-                       // sentinel value (if it's size 1) or the same
-                       // value encoded properly. Decode it to see if
-                       // it's the 1 byte sentinel value.
-                       _, size := DecodeRuneInString(s[i:])
-                       if size == 1 {
-                               return false
-                       }
+       n := len(s)
+       for i := 0; i < n; {
+               si := s[i]
+               if si < RuneSelf {
+                       i++
+                       continue
+               }
+               x := first[si]
+               if x == xx {
+                       return false // Illegal starter byte.
+               }
+               size := int(x & 7)
+               if i+size > n {
+                       return false // Short or invalid.
+               }
+               accept := acceptRanges[x>>4]
+               if c := s[i+1]; c < accept.lo || accept.hi < c {
+                       return false
+               } else if size == 2 {
+               } else if c := s[i+2]; c < locb || hicb < c {
+                       return false
+               } else if size == 3 {
+               } else if c := s[i+3]; c < locb || hicb < c {
+                       return false
                }
+               i += size
        }
        return true
 }
index 758d7a0f8e9bdb971308cbdd1a80e5113173dde5..51571b61eb9f501276b205109aa181368e61815e 100644 (file)
@@ -100,6 +100,15 @@ func TestFullRune(t *testing.T) {
                        t.Errorf("FullRune(%q) = true, want false", s1)
                }
        }
+       for _, s := range []string{"\xc0", "\xc1"} {
+               b := []byte(s)
+               if !FullRune(b) {
+                       t.Errorf("FullRune(%q) = false, want true", s)
+               }
+               if !FullRuneInString(s) {
+                       t.Errorf("FullRuneInString(%q) = false, want true", s)
+               }
+       }
 }
 
 func TestEncodeRune(t *testing.T) {
@@ -300,6 +309,8 @@ var runecounttests = []RuneCountTest{
        {"☺☻☹", 3},
        {"1,2,3,4", 7},
        {"\xe2\x00", 2},
+       {"\xe2\x80", 2},
+       {"a\xe2\x80", 3},
 }
 
 func TestRuneCount(t *testing.T) {
@@ -352,6 +363,7 @@ var validTests = []ValidTest{
        {"ЖЖ", true},
        {"брэд-ЛГТМ", true},
        {"☺☻☹", true},
+       {"aa\xe2", false},
        {string([]byte{66, 250}), false},
        {string([]byte{66, 250, 67}), false},
        {"a\uFFFDb", true},
@@ -404,17 +416,57 @@ func TestValidRune(t *testing.T) {
 }
 
 func BenchmarkRuneCountTenASCIIChars(b *testing.B) {
+       s := []byte("0123456789")
        for i := 0; i < b.N; i++ {
-               RuneCountInString("0123456789")
+               RuneCount(s)
        }
 }
 
 func BenchmarkRuneCountTenJapaneseChars(b *testing.B) {
+       s := []byte("日本語日本語日本語日")
+       for i := 0; i < b.N; i++ {
+               RuneCount(s)
+       }
+}
+
+func BenchmarkRuneCountInStringTenASCIIChars(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               RuneCountInString("0123456789")
+       }
+}
+
+func BenchmarkRuneCountInStringTenJapaneseChars(b *testing.B) {
        for i := 0; i < b.N; i++ {
                RuneCountInString("日本語日本語日本語日")
        }
 }
 
+func BenchmarkValidTenASCIIChars(b *testing.B) {
+       s := []byte("0123456789")
+       for i := 0; i < b.N; i++ {
+               Valid(s)
+       }
+}
+
+func BenchmarkValidTenJapaneseChars(b *testing.B) {
+       s := []byte("日本語日本語日本語日")
+       for i := 0; i < b.N; i++ {
+               Valid(s)
+       }
+}
+
+func BenchmarkValidStringTenASCIIChars(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               ValidString("0123456789")
+       }
+}
+
+func BenchmarkValidStringTenJapaneseChars(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               ValidString("日本語日本語日本語日")
+       }
+}
+
 func BenchmarkEncodeASCIIRune(b *testing.B) {
        buf := make([]byte, UTFMax)
        for i := 0; i < b.N; i++ {
@@ -442,3 +494,17 @@ func BenchmarkDecodeJapaneseRune(b *testing.B) {
                DecodeRune(nihon)
        }
 }
+
+func BenchmarkFullASCIIRune(b *testing.B) {
+       a := []byte{'a'}
+       for i := 0; i < b.N; i++ {
+               FullRune(a)
+       }
+}
+
+func BenchmarkFullJapaneseRune(b *testing.B) {
+       nihon := []byte("本")
+       for i := 0; i < b.N; i++ {
+               FullRune(nihon)
+       }
+}
index 4a1bf5636e50ec77dcf307a6b66a5569bbb5ba04..a948c31cca096ae7c1c2a497a2b37f813742c444 100644 (file)
@@ -33,105 +33,107 @@ extern void __splitstack_setcontext(void *context[10]);
 #define D SigDefault
 
 /* Signal actions.  This collects the sigtab tables for several
-   different targets from the master library.  SIGKILL, SIGCONT, and
-   SIGSTOP are not listed, as we don't want to set signal handlers for
-   them.  */
+   different targets from the master library.  SIGKILL and SIGSTOP are
+   not listed, as we don't want to set signal handlers for them.  */
 
 SigTab runtime_sigtab[] = {
 #ifdef SIGHUP
-  { SIGHUP,    N + K },
+  { SIGHUP,    N + K, NULL },
 #endif
 #ifdef SIGINT
-  { SIGINT,    N + K },
+  { SIGINT,    N + K, NULL  },
 #endif
 #ifdef SIGQUIT
-  { SIGQUIT,   N + T },
+  { SIGQUIT,   N + T, NULL  },
 #endif
 #ifdef SIGILL
-  { SIGILL,    T },
+  { SIGILL,    T, NULL  },
 #endif
 #ifdef SIGTRAP
-  { SIGTRAP,   T },
+  { SIGTRAP,   T, NULL  },
 #endif
 #ifdef SIGABRT
-  { SIGABRT,   N + T },
+  { SIGABRT,   N + T, NULL  },
 #endif
 #ifdef SIGBUS
-  { SIGBUS,    P },
+  { SIGBUS,    P, NULL  },
 #endif
 #ifdef SIGFPE
-  { SIGFPE,    P },
+  { SIGFPE,    P, NULL  },
 #endif
 #ifdef SIGUSR1
-  { SIGUSR1,   N },
+  { SIGUSR1,   N, NULL  },
 #endif
 #ifdef SIGSEGV
-  { SIGSEGV,   P },
+  { SIGSEGV,   P, NULL  },
 #endif
 #ifdef SIGUSR2
-  { SIGUSR2,   N },
+  { SIGUSR2,   N, NULL  },
 #endif
 #ifdef SIGPIPE
-  { SIGPIPE,   N },
+  { SIGPIPE,   N, NULL  },
 #endif
 #ifdef SIGALRM
-  { SIGALRM,   N },
+  { SIGALRM,   N, NULL  },
 #endif
 #ifdef SIGTERM
-  { SIGTERM,   N + K },
+  { SIGTERM,   N + K, NULL  },
 #endif
 #ifdef SIGSTKFLT
-  { SIGSTKFLT,         T },
+  { SIGSTKFLT,         T, NULL  },
 #endif
 #ifdef SIGCHLD
-  { SIGCHLD,   N },
+  { SIGCHLD,   N, NULL  },
+#endif
+#ifdef SIGCONT
+  { SIGCONT,   N + D, NULL  },
 #endif
 #ifdef SIGTSTP
-  { SIGTSTP,   N + D },
+  { SIGTSTP,   N + D, NULL  },
 #endif
 #ifdef SIGTTIN
-  { SIGTTIN,   N + D },
+  { SIGTTIN,   N + D, NULL  },
 #endif
 #ifdef SIGTTOU
-  { SIGTTOU,   N + D },
+  { SIGTTOU,   N + D, NULL  },
 #endif
 #ifdef SIGURG
-  { SIGURG,    N },
+  { SIGURG,    N, NULL  },
 #endif
 #ifdef SIGXCPU
-  { SIGXCPU,   N },
+  { SIGXCPU,   N, NULL  },
 #endif
 #ifdef SIGXFSZ
-  { SIGXFSZ,   N },
+  { SIGXFSZ,   N, NULL  },
 #endif
 #ifdef SIGVTALRM
-  { SIGVTALRM,         N },
+  { SIGVTALRM,         N, NULL  },
 #endif
 #ifdef SIGPROF
-  { SIGPROF,   N },
+  { SIGPROF,   N, NULL  },
 #endif
 #ifdef SIGWINCH
-  { SIGWINCH,  N },
+  { SIGWINCH,  N, NULL  },
 #endif
 #ifdef SIGIO
-  { SIGIO,     N },
+  { SIGIO,     N, NULL  },
 #endif
 #ifdef SIGPWR
-  { SIGPWR,    N },
+  { SIGPWR,    N, NULL  },
 #endif
 #ifdef SIGSYS
-  { SIGSYS,    N },
+  { SIGSYS,    N, NULL  },
 #endif
 #ifdef SIGEMT
-  { SIGEMT,    T },
+  { SIGEMT,    T, NULL  },
 #endif
 #ifdef SIGINFO
-  { SIGINFO,   N },
+  { SIGINFO,   N, NULL  },
 #endif
 #ifdef SIGTHR
-  { SIGTHR,    N },
+  { SIGTHR,    N, NULL  },
 #endif
-  { -1,                0 }
+  { -1,                0, NULL  }
 };
 #undef N
 #undef K
@@ -526,6 +528,9 @@ os_sigpipe (void)
   struct sigaction sa;
   int i;
 
+  if (__go_sigsend (SIGPIPE))
+    return;
+
   memset (&sa, 0, sizeof sa);
 
   sa.sa_handler = SIG_DFL;
index be7ccbd61359bc291ec5ea7e1ac437a351fb150e..4140d33d04157f2a049d576483cc4ebd8eda6cee 100644 (file)
@@ -20,23 +20,28 @@ enum {
 // The cached value is a uint32 in which the low bit
 // is the "crash" setting and the top 31 bits are the
 // gotraceback value.
-static uint32 traceback_cache = ~(uint32)0;
+enum {
+       tracebackCrash = 1 << 0,
+       tracebackAll = 1 << 1,
+       tracebackShift = 2,
+};
+static uint32 traceback_cache = 2 << tracebackShift;
+static uint32 traceback_env;
 
 extern volatile intgo runtime_MemProfileRate
   __asm__ (GOSYM_PREFIX "runtime.MemProfileRate");
 
 
-// The GOTRACEBACK environment variable controls the
-// behavior of a Go program that is crashing and exiting.
-//     GOTRACEBACK=0   suppress all tracebacks
-//     GOTRACEBACK=1   default behavior - show tracebacks but exclude runtime frames
-//     GOTRACEBACK=2   show tracebacks including runtime frames
-//     GOTRACEBACK=crash   show tracebacks including runtime frames, then crash (core dump etc)
+// gotraceback returns the current traceback settings.
+//
+// If level is 0, suppress all tracebacks.
+// If level is 1, show tracebacks, but exclude runtime frames.
+// If level is 2, show tracebacks including runtime frames.
+// If all is set, print all goroutine stacks. Otherwise, print just the current goroutine.
+// If crash is set, crash (core dump, etc) after tracebacking.
 int32
 runtime_gotraceback(bool *crash)
 {
-       String s;
-       const byte *p;
        uint32 x;
 
        if(crash != nil)
@@ -44,20 +49,9 @@ runtime_gotraceback(bool *crash)
        if(runtime_m()->traceback != 0)
                return runtime_m()->traceback;
        x = runtime_atomicload(&traceback_cache);
-       if(x == ~(uint32)0) {
-               s = runtime_getenv("GOTRACEBACK");
-               p = s.str;
-               if(s.len == 0)
-                       x = 1<<1;
-               else if(s.len == 5 && runtime_strcmp((const char *)p, "crash") == 0)
-                       x = (2<<1) | 1;
-               else
-                       x = runtime_atoi(p, s.len)<<1;  
-               runtime_atomicstore(&traceback_cache, x);
-       }
        if(crash != nil)
-               *crash = x&1;
-       return x>>1;
+               *crash = x&tracebackCrash;
+       return x>>tracebackShift;
 }
 
 static int32   argc;
@@ -319,6 +313,31 @@ runtime_signalstack(byte *p, int32 n)
                *(int *)0xf1 = 0xf1;
 }
 
+void setTraceback(String level)
+  __asm__ (GOSYM_PREFIX "runtime_debug.SetTraceback");
+
+void setTraceback(String level) {
+       uint32 t;
+
+       if (level.len == 4 && __builtin_memcmp(level.str, "none", 4) == 0) {
+               t = 0;
+       } else if (level.len == 0 || (level.len == 6 && __builtin_memcmp(level.str, "single", 6) == 0)) {
+               t = 1 << tracebackShift;
+       } else if (level.len == 3 && __builtin_memcmp(level.str, "all", 3) == 0) {
+               t = (1<<tracebackShift) | tracebackAll;
+       } else if (level.len == 6 && __builtin_memcmp(level.str, "system", 6) == 0) {
+               t = (2<<tracebackShift) | tracebackAll;
+       } else if (level.len == 5 && __builtin_memcmp(level.str, "crash", 5) == 0) {
+               t = (2<<tracebackShift) | tracebackAll | tracebackCrash;
+       } else {
+               t = (runtime_atoi(level.str, level.len)<<tracebackShift) | tracebackAll;
+       }
+
+       t |= traceback_env;
+
+       runtime_atomicstore(&traceback_cache, t);
+}
+
 DebugVars      runtime_debug;
 
 // Holds variables parsed from GODEBUG env var,
@@ -331,11 +350,22 @@ static struct {
        int32*  value;
 } dbgvar[] = {
        {"allocfreetrace", &runtime_debug.allocfreetrace},
+       {"cgocheck", &runtime_debug.cgocheck},
        {"efence", &runtime_debug.efence},
+       {"gccheckmark", &runtime_debug.gccheckmark},
+       {"gcpacertrace", &runtime_debug.gcpacertrace},
+       {"gcshrinkstackoff", &runtime_debug.gcshrinkstackoff},
+       {"gcstackbarrieroff", &runtime_debug.gcstackbarrieroff},
+       {"gcstackbarrierall", &runtime_debug.gcstackbarrierall},
+       {"gcstoptheworld", &runtime_debug.gcstoptheworld},
        {"gctrace", &runtime_debug.gctrace},
        {"gcdead", &runtime_debug.gcdead},
+       {"invalidptr", &runtime_debug.invalidptr},
+       {"sbrk", &runtime_debug.sbrk},
+       {"scavenge", &runtime_debug.scavenge},
        {"scheddetail", &runtime_debug.scheddetail},
        {"schedtrace", &runtime_debug.schedtrace},
+       {"wbshadow", &runtime_debug.wbshadow},
 };
 
 void
@@ -345,17 +375,7 @@ runtime_parsedebugvars(void)
        const byte *p, *pn;
        intgo len;
        intgo i, n;
-       bool tmp;
        
-       // gotraceback caches the GOTRACEBACK setting in traceback_cache.
-       // gotraceback can be called before the environment is available.
-       // traceback_cache must be reset after the environment is made
-       // available, in order for the environment variable to take effect.
-       // The code is fixed differently in Go 1.4.
-       // This is a limited fix for Go 1.3.3.
-       traceback_cache = ~(uint32)0;
-       runtime_gotraceback(&tmp);
-
        s = runtime_getenv("GODEBUG");
        if(s.len == 0)
                return;
@@ -378,6 +398,20 @@ runtime_parsedebugvars(void)
                len -= (pn - p) - 1;
                p = pn + 1;
        }
+
+       setTraceback(runtime_getenv("GOTRACEBACK"));
+       traceback_env = traceback_cache;
+}
+
+// SetTracebackEnv is like runtime/debug.SetTraceback, but it raises
+// the "environment" traceback level, so later calls to
+// debug.SetTraceback (e.g., from testing timeouts) can't lower it.
+void SetTracebackEnv(String level)
+  __asm__ (GOSYM_PREFIX "runtime.SetTracebackEnv");
+
+void SetTracebackEnv(String level) {
+       setTraceback(level);
+       traceback_env = traceback_cache;
 }
 
 // Poor mans 64-bit division.
index cbf1fe160b960188cdb530173dc3a57e3132a510..f4b170d2d0eb8fcc0e3db03cec828a4f6a3f0936 100644 (file)
@@ -329,6 +329,7 @@ struct      SigTab
 {
        int32   sig;
        int32   flags;
+       void*   fwdsig;
 };
 enum
 {
@@ -338,8 +339,7 @@ enum
        SigPanic = 1<<3,        // if the signal is from the kernel, panic
        SigDefault = 1<<4,      // if the signal isn't explicitly requested, don't monitor it
        SigHandling = 1<<5,     // our signal handler is registered
-       SigIgnored = 1<<6,      // the signal was ignored before we registered for it
-       SigGoExit = 1<<7,       // cause all runtime procs to exit (only used on Plan 9).
+       SigGoExit = 1<<6,       // cause all runtime procs to exit (only used on Plan 9).
 };
 
 // Layout of in-memory per-function information prepared by linker
@@ -450,11 +450,22 @@ struct CgoMal
 struct DebugVars
 {
        int32   allocfreetrace;
+       int32   cgocheck;
        int32   efence;
+       int32   gccheckmark;
+       int32   gcpacertrace;
+       int32   gcshrinkstackoff;
+       int32   gcstackbarrieroff;
+       int32   gcstackbarrierall;
+       int32   gcstoptheworld;
        int32   gctrace;
        int32   gcdead;
+       int32   invalidptr;
+       int32   sbrk;
+       int32   scavenge;
        int32   scheddetail;
        int32   schedtrace;
+       int32   wbshadow;
 };
 
 extern bool runtime_precisestack;
index 43be0d85771aba9fb718181b78d93d5ed13af40a..20289335f8dc5835a8a4a0a7810f06ab4ae9a6f5 100644 (file)
@@ -24,14 +24,15 @@ runtime_initsig(void)
                if((t->flags == 0) || (t->flags & SigDefault))
                        continue;
 
+               t->fwdsig = runtime_getsig(i);
+
                // For some signals, we respect an inherited SIG_IGN handler
                // rather than insist on installing our own default handler.
                // Even these signals can be fetched using the os/signal package.
                switch(t->sig) {
                case SIGHUP:
                case SIGINT:
-                       if(runtime_getsig(i) == GO_SIG_IGN) {
-                               t->flags = SigNotify | SigIgnored;
+                       if(t->fwdsig == GO_SIG_IGN) {
                                continue;
                        }
                }
@@ -60,8 +61,7 @@ runtime_sigenable(uint32 sig)
 
        if((t->flags & SigNotify) && !(t->flags & SigHandling)) {
                t->flags |= SigHandling;
-               if(runtime_getsig(i) == GO_SIG_IGN)
-                       t->flags |= SigIgnored;
+               t->fwdsig = runtime_getsig(i);
                runtime_setsig(i, runtime_sighandler, true);
        }
 }
@@ -83,12 +83,9 @@ runtime_sigdisable(uint32 sig)
        if(t == nil)
                return;
 
-       if((t->flags & SigNotify) && (t->flags & SigHandling)) {
+       if((sig == SIGHUP || sig == SIGINT) && t->fwdsig == GO_SIG_IGN) {
                t->flags &= ~SigHandling;
-               if(t->flags & SigIgnored)
-                       runtime_setsig(i, GO_SIG_IGN, true);
-               else
-                       runtime_setsig(i, GO_SIG_DFL, true);
+               runtime_setsig(i, t->fwdsig, true);
        }
 }
 
@@ -132,18 +129,6 @@ runtime_resetcpuprofiler(int32 hz)
        runtime_m()->profilehz = hz;
 }
 
-void
-os_sigpipe(void)
-{
-       int32 i;
-
-       for(i = 0; runtime_sigtab[i].sig != -1; i++)
-               if(runtime_sigtab[i].sig == SIGPIPE)
-                       break;
-       runtime_setsig(i, GO_SIG_DFL, false);
-       runtime_raise(SIGPIPE);
-}
-
 void
 runtime_unblocksignals(void)
 {