libgo: Update to current master library sources.

From-SVN: r194460
This commit is contained in:
Ian Lance Taylor 2012-12-12 23:13:29 +00:00
parent bc77608b97
commit a42a906c42
145 changed files with 6245 additions and 1920 deletions

View File

@ -1,4 +1,4 @@
a070de932857
c031aa767edf
The first line of this file holds the Mercurial revision number of the
last merge done from the master library sources.

View File

@ -221,6 +221,7 @@ endif
toolexeclibgoexpdir = $(toolexeclibgodir)/exp
toolexeclibgoexp_DATA = \
exp/cookiejar.gox \
exp/ebnf.gox \
exp/html.gox \
$(exp_inotify_gox) \
@ -251,6 +252,7 @@ toolexeclibgogo_DATA = \
go/ast.gox \
go/build.gox \
go/doc.gox \
go/format.gox \
go/parser.gox \
go/printer.gox \
go/scanner.gox \
@ -1194,6 +1196,9 @@ go_encoding_xml_files = \
go/encoding/xml/typeinfo.go \
go/encoding/xml/xml.go
go_exp_cookiejar_files = \
go/exp/cookiejar/jar.go \
go/exp/cookiejar/storage.go
go_exp_ebnf_files = \
go/exp/ebnf/ebnf.go \
go/exp/ebnf/parser.go
@ -1284,6 +1289,8 @@ go_go_doc_files = \
go/go/doc/filter.go \
go/go/doc/reader.go \
go/go/doc/synopsis.go
go_go_format_files = \
go/go/format/format.go
go_go_parser_files = \
go/go/parser/interface.go \
go/go/parser/parser.go
@ -1384,6 +1391,7 @@ go_math_rand_files = \
go_mime_multipart_files = \
go/mime/multipart/formdata.go \
go/mime/multipart/multipart.go \
go/mime/multipart/quotedprintable.go \
go/mime/multipart/writer.go
go_net_http_files = \
@ -1456,6 +1464,7 @@ go_os_signal_files = \
go_os_user_files = \
go/os/user/user.go \
go/os/user/lookup.go \
go/os/user/lookup_unix.go
go_path_filepath_files = \
@ -1822,6 +1831,7 @@ libgo_go_objs = \
encoding/json.lo \
encoding/pem.lo \
encoding/xml.lo \
exp/cookiejar.lo \
exp/ebnf.lo \
exp/html.lo \
exp/html/atom.lo \
@ -1836,6 +1846,7 @@ libgo_go_objs = \
go/ast.lo \
go/build.lo \
go/doc.lo \
go/format.lo \
go/parser.lo \
go/printer.lo \
go/scanner.lo \
@ -2658,6 +2669,15 @@ encoding/xml/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: encoding/xml/check
@go_include@ exp/cookiejar.lo.dep
exp/cookiejar.lo.dep: $(go_exp_cookiejar_files)
$(BUILDDEPS)
exp/cookiejar.lo: $(go_exp_cookiejar_files)
$(BUILDPACKAGE)
exp/cookiejar/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/cookiejar/check
@go_include@ exp/ebnf.lo.dep
exp/ebnf.lo.dep: $(go_exp_ebnf_files)
$(BUILDDEPS)
@ -2802,6 +2822,15 @@ go/doc/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: go/doc/check
@go_include@ go/format.lo.dep
go/format.lo.dep: $(go_go_format_files)
$(BUILDDEPS)
go/format.lo: $(go_go_format_files)
$(BUILDPACKAGE)
go/format/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: go/format/check
@go_include@ go/parser.lo.dep
go/parser.lo.dep: $(go_go_parser_files)
$(BUILDDEPS)
@ -3450,6 +3479,8 @@ encoding/pem.gox: encoding/pem.lo
encoding/xml.gox: encoding/xml.lo
$(BUILDGOX)
exp/cookiejar.gox: exp/cookiejar.lo
$(BUILDGOX)
exp/ebnf.gox: exp/ebnf.lo
$(BUILDGOX)
exp/html.gox: exp/html.lo
@ -3482,6 +3513,8 @@ go/build.gox: go/build.lo
$(BUILDGOX)
go/doc.gox: go/doc.lo
$(BUILDGOX)
go/format.gox: go/format.lo
$(BUILDGOX)
go/parser.gox: go/parser.lo
$(BUILDGOX)
go/printer.gox: go/printer.lo
@ -3681,6 +3714,7 @@ TEST_PACKAGES = \
encoding/json/check \
encoding/pem/check \
encoding/xml/check \
exp/cookiejar/check \
exp/ebnf/check \
exp/html/check \
exp/html/atom/check \
@ -3696,6 +3730,7 @@ TEST_PACKAGES = \
go/ast/check \
$(go_build_check_omitted_since_it_calls_6g) \
go/doc/check \
go/format/check \
go/parser/check \
go/printer/check \
go/scanner/check \

View File

@ -153,26 +153,27 @@ am__DEPENDENCIES_2 = bufio.lo bytes.lo bytes/index.lo crypto.lo \
debug/pe.lo encoding/ascii85.lo encoding/asn1.lo \
encoding/base32.lo encoding/base64.lo encoding/binary.lo \
encoding/csv.lo encoding/gob.lo encoding/hex.lo \
encoding/json.lo encoding/pem.lo encoding/xml.lo exp/ebnf.lo \
exp/html.lo exp/html/atom.lo exp/locale/collate.lo \
exp/locale/collate/build.lo exp/norm.lo exp/proxy.lo \
exp/terminal.lo exp/types.lo exp/utf8string.lo \
html/template.lo go/ast.lo go/build.lo go/doc.lo go/parser.lo \
go/printer.lo go/scanner.lo go/token.lo hash/adler32.lo \
hash/crc32.lo hash/crc64.lo hash/fnv.lo net/http/cgi.lo \
net/http/fcgi.lo net/http/httptest.lo net/http/httputil.lo \
net/http/pprof.lo image/color.lo image/draw.lo image/gif.lo \
image/jpeg.lo image/png.lo index/suffixarray.lo io/ioutil.lo \
log/syslog.lo log/syslog/syslog_c.lo math/big.lo math/cmplx.lo \
math/rand.lo mime/multipart.lo net/http.lo net/mail.lo \
net/rpc.lo net/smtp.lo net/textproto.lo net/url.lo \
old/netchan.lo old/regexp.lo old/template.lo os/exec.lo \
$(am__DEPENDENCIES_1) os/signal.lo os/user.lo path/filepath.lo \
regexp/syntax.lo net/rpc/jsonrpc.lo runtime/debug.lo \
runtime/pprof.lo sync/atomic.lo sync/atomic_c.lo \
text/scanner.lo text/tabwriter.lo text/template.lo \
text/template/parse.lo testing/iotest.lo testing/quick.lo \
unicode/utf16.lo unicode/utf8.lo
encoding/json.lo encoding/pem.lo encoding/xml.lo \
exp/cookiejar.lo exp/ebnf.lo exp/html.lo exp/html/atom.lo \
exp/locale/collate.lo exp/locale/collate/build.lo exp/norm.lo \
exp/proxy.lo exp/terminal.lo exp/types.lo exp/utf8string.lo \
html/template.lo go/ast.lo go/build.lo go/doc.lo go/format.lo \
go/parser.lo go/printer.lo go/scanner.lo go/token.lo \
hash/adler32.lo hash/crc32.lo hash/crc64.lo hash/fnv.lo \
net/http/cgi.lo net/http/fcgi.lo net/http/httptest.lo \
net/http/httputil.lo net/http/pprof.lo image/color.lo \
image/draw.lo image/gif.lo image/jpeg.lo image/png.lo \
index/suffixarray.lo io/ioutil.lo log/syslog.lo \
log/syslog/syslog_c.lo math/big.lo math/cmplx.lo math/rand.lo \
mime/multipart.lo net/http.lo net/mail.lo net/rpc.lo \
net/smtp.lo net/textproto.lo net/url.lo old/netchan.lo \
old/regexp.lo old/template.lo os/exec.lo $(am__DEPENDENCIES_1) \
os/signal.lo os/user.lo path/filepath.lo regexp/syntax.lo \
net/rpc/jsonrpc.lo runtime/debug.lo runtime/pprof.lo \
sync/atomic.lo sync/atomic_c.lo text/scanner.lo \
text/tabwriter.lo text/template.lo text/template/parse.lo \
testing/iotest.lo testing/quick.lo unicode/utf16.lo \
unicode/utf8.lo
libgo_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
../libbacktrace/libbacktrace.la $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
@ -608,6 +609,7 @@ toolexeclibgoencoding_DATA = \
@LIBGO_IS_LINUX_TRUE@exp_inotify_gox =
toolexeclibgoexpdir = $(toolexeclibgodir)/exp
toolexeclibgoexp_DATA = \
exp/cookiejar.gox \
exp/ebnf.gox \
exp/html.gox \
$(exp_inotify_gox) \
@ -634,6 +636,7 @@ toolexeclibgogo_DATA = \
go/ast.gox \
go/build.gox \
go/doc.gox \
go/format.gox \
go/parser.gox \
go/printer.gox \
go/scanner.gox \
@ -1403,6 +1406,10 @@ go_encoding_xml_files = \
go/encoding/xml/typeinfo.go \
go/encoding/xml/xml.go
go_exp_cookiejar_files = \
go/exp/cookiejar/jar.go \
go/exp/cookiejar/storage.go
go_exp_ebnf_files = \
go/exp/ebnf/ebnf.go \
go/exp/ebnf/parser.go
@ -1506,6 +1513,9 @@ 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_parser_files = \
go/go/parser/interface.go \
go/go/parser/parser.go
@ -1614,6 +1624,7 @@ go_math_rand_files = \
go_mime_multipart_files = \
go/mime/multipart/formdata.go \
go/mime/multipart/multipart.go \
go/mime/multipart/quotedprintable.go \
go/mime/multipart/writer.go
go_net_http_files = \
@ -1695,6 +1706,7 @@ go_os_signal_files = \
go_os_user_files = \
go/os/user/user.go \
go/os/user/lookup.go \
go/os/user/lookup_unix.go
go_path_filepath_files = \
@ -1948,6 +1960,7 @@ libgo_go_objs = \
encoding/json.lo \
encoding/pem.lo \
encoding/xml.lo \
exp/cookiejar.lo \
exp/ebnf.lo \
exp/html.lo \
exp/html/atom.lo \
@ -1962,6 +1975,7 @@ libgo_go_objs = \
go/ast.lo \
go/build.lo \
go/doc.lo \
go/format.lo \
go/parser.lo \
go/printer.lo \
go/scanner.lo \
@ -2200,6 +2214,7 @@ TEST_PACKAGES = \
encoding/json/check \
encoding/pem/check \
encoding/xml/check \
exp/cookiejar/check \
exp/ebnf/check \
exp/html/check \
exp/html/atom/check \
@ -2215,6 +2230,7 @@ TEST_PACKAGES = \
go/ast/check \
$(go_build_check_omitted_since_it_calls_6g) \
go/doc/check \
go/format/check \
go/parser/check \
go/printer/check \
go/scanner/check \
@ -5096,6 +5112,15 @@ encoding/xml/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: encoding/xml/check
@go_include@ exp/cookiejar.lo.dep
exp/cookiejar.lo.dep: $(go_exp_cookiejar_files)
$(BUILDDEPS)
exp/cookiejar.lo: $(go_exp_cookiejar_files)
$(BUILDPACKAGE)
exp/cookiejar/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/cookiejar/check
@go_include@ exp/ebnf.lo.dep
exp/ebnf.lo.dep: $(go_exp_ebnf_files)
$(BUILDDEPS)
@ -5240,6 +5265,15 @@ go/doc/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: go/doc/check
@go_include@ go/format.lo.dep
go/format.lo.dep: $(go_go_format_files)
$(BUILDDEPS)
go/format.lo: $(go_go_format_files)
$(BUILDPACKAGE)
go/format/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: go/format/check
@go_include@ go/parser.lo.dep
go/parser.lo.dep: $(go_go_parser_files)
$(BUILDDEPS)
@ -5880,6 +5914,8 @@ encoding/pem.gox: encoding/pem.lo
encoding/xml.gox: encoding/xml.lo
$(BUILDGOX)
exp/cookiejar.gox: exp/cookiejar.lo
$(BUILDGOX)
exp/ebnf.gox: exp/ebnf.lo
$(BUILDGOX)
exp/html.gox: exp/html.lo
@ -5912,6 +5948,8 @@ go/build.gox: go/build.lo
$(BUILDGOX)
go/doc.gox: go/doc.lo
$(BUILDGOX)
go/format.gox: go/format.lo
$(BUILDGOX)
go/parser.gox: go/parser.lo
$(BUILDGOX)
go/printer.gox: go/printer.lo

View File

@ -64,6 +64,8 @@ func NewReader(rd io.Reader) *Reader {
return NewReaderSize(rd, defaultBufSize)
}
var errNegativeRead = errors.New("bufio: reader returned negative count from Read")
// fill reads a new chunk into the buffer.
func (b *Reader) fill() {
// Slide existing data to beginning.
@ -75,6 +77,9 @@ func (b *Reader) fill() {
// Read new data.
n, e := b.rd.Read(b.buf[b.w:])
if n < 0 {
panic(errNegativeRead)
}
b.w += n
if e != nil {
b.err = e
@ -282,6 +287,9 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
// of the line. The returned buffer is only valid until the next call to
// ReadLine. ReadLine either returns a non-nil line or it returns an error,
// never both.
//
// The text returned from ReadLine does not include the line end ("\r\n" or "\n").
// No indication or error is given if the input ends without a final line end.
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) {
line, err = b.ReadSlice('\n')
if err == ErrBufferFull {

View File

@ -939,6 +939,29 @@ func (w *writeCountingDiscard) Write(p []byte) (int, error) {
return len(p), nil
}
type negativeReader int
func (r *negativeReader) Read([]byte) (int, error) { return -1, nil }
func TestNegativeRead(t *testing.T) {
// should panic with a description pointing at the reader, not at itself.
// (should NOT panic with slice index error, for example.)
b := NewReader(new(negativeReader))
defer func() {
switch err := recover().(type) {
case nil:
t.Fatal("read did not panic")
case error:
if !strings.Contains(err.Error(), "reader returned negative count from Read") {
t.Fatal("wrong panic: %v", err)
}
default:
t.Fatalf("unexpected panic value: %T(%v)", err, err)
}
}()
b.Read(make([]byte, 100))
}
// An onlyReader only implements io.Reader, no matter what other methods the underlying implementation may have.
type onlyReader struct {
r io.Reader

View File

@ -360,16 +360,24 @@ func (b *Buffer) UnreadByte() error {
// ReadBytes returns err != nil if and only if the returned data does not end in
// delim.
func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) {
slice, err := b.readSlice(delim)
// return a copy of slice. The buffer's backing array may
// be overwritten by later calls.
line = append(line, slice...)
return
}
// readSlice is like readBytes but returns a reference to internal buffer data.
func (b *Buffer) readSlice(delim byte) (line []byte, err error) {
i := IndexByte(b.buf[b.off:], delim)
size := i + 1
end := b.off + i + 1
if i < 0 {
size = len(b.buf) - b.off
end = len(b.buf)
err = io.EOF
}
line = make([]byte, size)
copy(line, b.buf[b.off:])
b.off += size
return
line = b.buf[b.off:end]
b.off = end
return line, err
}
// ReadString reads until the first occurrence of delim in the input,
@ -379,8 +387,8 @@ func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) {
// ReadString returns err != nil if and only if the returned data does not end
// in delim.
func (b *Buffer) ReadString(delim byte) (line string, err error) {
bytes, err := b.ReadBytes(delim)
return string(bytes), err
slice, err := b.readSlice(delim)
return string(slice), err
}
// NewBuffer creates and initializes a new Buffer using buf as its initial

View File

@ -375,6 +375,41 @@ func TestReadBytes(t *testing.T) {
}
}
func TestReadString(t *testing.T) {
for _, test := range readBytesTests {
buf := NewBufferString(test.buffer)
var err error
for _, expected := range test.expected {
var s string
s, err = buf.ReadString(test.delim)
if s != expected {
t.Errorf("expected %q, got %q", expected, s)
}
if err != nil {
break
}
}
if err != test.err {
t.Errorf("expected error %v, got %v", test.err, err)
}
}
}
func BenchmarkReadString(b *testing.B) {
const n = 32 << 10
data := make([]byte, n)
data[n-1] = 'x'
b.SetBytes(int64(n))
for i := 0; i < b.N; i++ {
buf := NewBuffer(data)
_, err := buf.ReadString('x')
if err != nil {
b.Fatal(err)
}
}
}
func TestGrow(t *testing.T) {
x := []byte{'x'}
y := []byte{'y'}

View File

@ -125,7 +125,7 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) {
func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
r.prevRune = -1
if r.i >= len(r.s) {
return 0, io.EOF
return 0, nil
}
b := r.s[r.i:]
m, err := w.Write(b)

View File

@ -8,6 +8,7 @@ import (
. "bytes"
"fmt"
"io"
"io/ioutil"
"os"
"testing"
)
@ -88,16 +89,20 @@ func TestReaderAt(t *testing.T) {
}
func TestReaderWriteTo(t *testing.T) {
for i := 3; i < 30; i += 3 {
s := data[:len(data)/i]
r := NewReader(testBytes[:len(testBytes)/i])
for i := 0; i < 30; i += 3 {
var l int
if i > 0 {
l = len(data) / i
}
s := data[:l]
r := NewReader(testBytes[:l])
var b Buffer
n, err := r.WriteTo(&b)
if expect := int64(len(s)); n != expect {
t.Errorf("got %v; want %v", n, expect)
}
if err != nil {
t.Errorf("got error = %v; want nil", err)
t.Errorf("for length %d: got error = %v; want nil", l, err)
}
if b.String() != s {
t.Errorf("got string %q; want %q", b.String(), s)
@ -107,3 +112,26 @@ func TestReaderWriteTo(t *testing.T) {
}
}
}
// verify that copying from an empty reader always has the same results,
// regardless of the presence of a WriteTo method.
func TestReaderCopyNothing(t *testing.T) {
type nErr struct {
n int64
err error
}
type justReader struct {
io.Reader
}
type justWriter struct {
io.Writer
}
discard := justWriter{ioutil.Discard} // hide ReadFrom
var with, withOut nErr
with.n, with.err = io.Copy(discard, NewReader(nil))
withOut.n, withOut.err = io.Copy(discard, justReader{NewReader(nil)})
if with != withOut {
t.Errorf("behavior differs: with = %#v; without: %#v", with, withOut)
}
}

View File

@ -37,15 +37,10 @@ func (pq PriorityQueue) Swap(i, j int) {
func (pq *PriorityQueue) Push(x interface{}) {
// Push and Pop use pointer receivers because they modify the slice's length,
// not just its contents.
// To simplify indexing expressions in these methods, we save a copy of the
// slice object. We could instead write (*pq)[i].
a := *pq
n := len(a)
a = a[0 : n+1]
n := len(*pq)
item := x.(*Item)
item.index = n
a[n] = item
*pq = a
*pq = append(*pq, item)
}
func (pq *PriorityQueue) Pop() interface{} {

View File

@ -74,7 +74,7 @@ func New(n int) *Ring {
return r
}
// Link connects ring r with with ring s such that r.Next()
// Link connects ring r with ring s such that r.Next()
// becomes s and returns the original value for r.Next().
// r must not be empty.
//

View File

@ -758,8 +758,28 @@ func (c *Conn) Write(b []byte) (int, error) {
return 0, alertInternalError
}
// SSL 3.0 and TLS 1.0 are susceptible to a chosen-plaintext
// attack when using block mode ciphers due to predictable IVs.
// This can be prevented by splitting each Application Data
// record into two records, effectively randomizing the IV.
//
// http://www.openssl.org/~bodo/tls-cbc.txt
// https://bugzilla.mozilla.org/show_bug.cgi?id=665814
// http://www.imperialviolet.org/2012/01/15/beastfollowup.html
var m int
if len(b) > 1 && c.vers <= versionTLS10 {
if _, ok := c.out.cipher.(cipher.BlockMode); ok {
n, err := c.writeRecord(recordTypeApplicationData, b[:1])
if err != nil {
return n, c.setError(err)
}
m, b = 1, b[1:]
}
}
n, err := c.writeRecord(recordTypeApplicationData, b)
return n, c.setError(err)
return n + m, c.setError(err)
}
// Read can be made to time out and return a net.Error with Timeout() == true

View File

@ -245,67 +245,24 @@ var ecdheAESClientScript = [][]byte{
0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
},
{
0x16, 0x03, 0x01, 0x00, 0x54, 0x02, 0x00, 0x00,
0x50, 0x03, 0x01, 0x50, 0x77, 0x31, 0xf7, 0x5b,
0xdb, 0x3d, 0x7a, 0x62, 0x76, 0x70, 0x95, 0x33,
0x73, 0x71, 0x13, 0xfe, 0xa3, 0xb1, 0xd8, 0xb3,
0x4d, 0x0d, 0xdc, 0xfe, 0x58, 0x6e, 0x6a, 0x3a,
0xf9, 0xde, 0xdc, 0x20, 0x8e, 0xfa, 0x3d, 0x60,
0xd0, 0xda, 0xa4, 0x0e, 0x36, 0xf0, 0xde, 0xb6,
0x81, 0xb4, 0x80, 0x5e, 0xf9, 0xd2, 0x4c, 0xec,
0xd1, 0x9c, 0x2a, 0x81, 0xc3, 0x36, 0x0b, 0x0f,
0x4a, 0x3d, 0xdf, 0x75, 0xc0, 0x13, 0x00, 0x00,
0x08, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01,
0x02, 0x16, 0x03, 0x01, 0x02, 0x39, 0x0b, 0x00,
0x02, 0x35, 0x00, 0x02, 0x32, 0x00, 0x02, 0x2f,
0x30, 0x82, 0x02, 0x2b, 0x30, 0x82, 0x01, 0xd5,
0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00,
0xb1, 0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92,
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e,
0x17, 0x0d, 0x31, 0x32, 0x30, 0x34, 0x30, 0x36,
0x31, 0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x17,
0x0d, 0x31, 0x35, 0x30, 0x34, 0x30, 0x36, 0x31,
0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x30, 0x45,
0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74,
0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x5c, 0x30,
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b,
0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0x9f, 0xb3,
0xc3, 0x84, 0x27, 0x95, 0xff, 0x12, 0x31, 0x52,
0x0f, 0x15, 0xef, 0x46, 0x11, 0xc4, 0xad, 0x80,
0xe6, 0x36, 0x5b, 0x0f, 0xdd, 0x80, 0xd7, 0x61,
0x8d, 0xe0, 0xfc, 0x72, 0x45, 0x09, 0x34, 0xfe,
0x55, 0x66, 0x45, 0x43, 0x4c, 0x68, 0x97, 0x6a,
0xfe, 0xa8, 0xa0, 0xa5, 0xdf, 0x5f, 0x78, 0xff,
0xee, 0xd7, 0x64, 0xb8, 0x3f, 0x04, 0xcb, 0x6f,
0xff, 0x2a, 0xfe, 0xfe, 0xb9, 0xed, 0x02, 0x03,
0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
0x04, 0x16, 0x04, 0x14, 0x78, 0xa6, 0x97, 0x9a,
0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22,
0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b,
0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
0x6e, 0x30, 0x6c, 0x80, 0x14, 0x78, 0xa6, 0x97,
0x9a, 0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba,
0x22, 0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc,
0x2b, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
0x16, 0x03, 0x01, 0x00, 0x52, 0x02, 0x00, 0x00,
0x4e, 0x03, 0x01, 0x50, 0xad, 0x72, 0xb1, 0x14,
0x45, 0xce, 0x0a, 0x95, 0xf9, 0x63, 0xef, 0xa8,
0xe5, 0x07, 0x34, 0x04, 0xe9, 0x08, 0x0f, 0x38,
0xe4, 0x28, 0x27, 0x91, 0x07, 0x03, 0xe2, 0xfe,
0xe3, 0x25, 0xf7, 0x20, 0x08, 0x42, 0xa2, 0x01,
0x69, 0x53, 0xf0, 0xd9, 0x4c, 0xfa, 0x01, 0xa1,
0xce, 0x4b, 0xf8, 0x28, 0x21, 0xad, 0x06, 0xbe,
0xe0, 0x1b, 0x3b, 0xf7, 0xec, 0xd2, 0x52, 0xae,
0x2a, 0x57, 0xb7, 0xa8, 0xc0, 0x13, 0x00, 0x00,
0x06, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x16,
0x03, 0x01, 0x02, 0x39, 0x0b, 0x00, 0x02, 0x35,
0x00, 0x02, 0x32, 0x00, 0x02, 0x2f, 0x30, 0x82,
0x02, 0x2b, 0x30, 0x82, 0x01, 0xd5, 0xa0, 0x03,
0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xb1, 0x35,
0x13, 0x65, 0x11, 0x20, 0xc5, 0x92, 0x30, 0x0d,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
@ -314,39 +271,82 @@ var ecdheAESClientScript = [][]byte{
0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0xb1,
0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92, 0x30,
0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
0x31, 0x32, 0x30, 0x34, 0x30, 0x36, 0x31, 0x37,
0x31, 0x30, 0x31, 0x33, 0x5a, 0x17, 0x0d, 0x31,
0x35, 0x30, 0x34, 0x30, 0x36, 0x31, 0x37, 0x31,
0x30, 0x31, 0x33, 0x5a, 0x30, 0x45, 0x31, 0x0b,
0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
0x4c, 0x74, 0x64, 0x30, 0x5c, 0x30, 0x0d, 0x06,
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, 0x85,
0x36, 0x40, 0x73, 0xc1, 0xbb, 0x1a, 0xda, 0xd4,
0x59, 0x9f, 0x2d, 0xa2, 0x70, 0x31, 0x46, 0x74,
0xec, 0x83, 0x6e, 0xa8, 0xc8, 0x3c, 0x51, 0xaf,
0x39, 0xac, 0xec, 0x40, 0xbc, 0xe8, 0x22, 0x46,
0x1d, 0x99, 0xd6, 0x46, 0x2a, 0x24, 0xd4, 0x8b,
0x05, 0x08, 0x4b, 0xfb, 0x35, 0x11, 0x6e, 0x92,
0xbb, 0x77, 0xba, 0xe4, 0x12, 0xbb, 0xf4, 0xc8,
0x5e, 0x9c, 0x81, 0xa8, 0x97, 0x60, 0x4c, 0x16,
0x03, 0x01, 0x00, 0x8b, 0x0c, 0x00, 0x00, 0x87,
0x03, 0x00, 0x17, 0x41, 0x04, 0xec, 0x06, 0x1f,
0xa0, 0x5e, 0x29, 0x49, 0x71, 0x8b, 0x04, 0x9f,
0x47, 0x87, 0xb1, 0xcb, 0xae, 0x57, 0x8f, 0xd7,
0xf6, 0xf8, 0x59, 0x74, 0x64, 0x5d, 0x3a, 0x08,
0xaf, 0x20, 0xc6, 0xd9, 0xfc, 0x5e, 0x36, 0x8b,
0x62, 0x0e, 0xdb, 0xee, 0xd8, 0xcd, 0xef, 0x25,
0x8a, 0x38, 0x88, 0x2d, 0x5c, 0x71, 0x50, 0x22,
0xda, 0x3f, 0x94, 0x06, 0xc9, 0x68, 0x5b, 0x78,
0x3d, 0x95, 0xca, 0x54, 0x44, 0x00, 0x40, 0x36,
0xcf, 0x10, 0x81, 0xb4, 0x32, 0x45, 0x3c, 0xa5,
0x2d, 0x3e, 0xb0, 0xf8, 0xf4, 0x51, 0xf5, 0x28,
0x09, 0x85, 0x71, 0xa6, 0x79, 0x71, 0x4b, 0x4e,
0xda, 0x32, 0x5a, 0xc7, 0xb3, 0x57, 0xfd, 0xe8,
0x12, 0xab, 0xd8, 0x29, 0xfb, 0x8b, 0x43, 0x8f,
0x7e, 0x27, 0x63, 0x91, 0x84, 0x9c, 0x51, 0x0c,
0x26, 0x7e, 0x36, 0x3b, 0x37, 0x8d, 0x8f, 0x9e,
0xe2, 0x82, 0x62, 0xbb, 0xe5, 0xdf, 0xfc, 0x16,
0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30,
0x48, 0x02, 0x41, 0x00, 0x9f, 0xb3, 0xc3, 0x84,
0x27, 0x95, 0xff, 0x12, 0x31, 0x52, 0x0f, 0x15,
0xef, 0x46, 0x11, 0xc4, 0xad, 0x80, 0xe6, 0x36,
0x5b, 0x0f, 0xdd, 0x80, 0xd7, 0x61, 0x8d, 0xe0,
0xfc, 0x72, 0x45, 0x09, 0x34, 0xfe, 0x55, 0x66,
0x45, 0x43, 0x4c, 0x68, 0x97, 0x6a, 0xfe, 0xa8,
0xa0, 0xa5, 0xdf, 0x5f, 0x78, 0xff, 0xee, 0xd7,
0x64, 0xb8, 0x3f, 0x04, 0xcb, 0x6f, 0xff, 0x2a,
0xfe, 0xfe, 0xb9, 0xed, 0x02, 0x03, 0x01, 0x00,
0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81, 0xa4, 0x30,
0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
0x04, 0x14, 0x78, 0xa6, 0x97, 0x9a, 0x63, 0xb5,
0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22, 0x7c, 0x23,
0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b, 0x30, 0x75,
0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x6e, 0x30,
0x6c, 0x80, 0x14, 0x78, 0xa6, 0x97, 0x9a, 0x63,
0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22, 0x7c,
0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b, 0xa1,
0x49, 0xa4, 0x47, 0x30, 0x45, 0x31, 0x0b, 0x30,
0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
0x74, 0x64, 0x82, 0x09, 0x00, 0xb1, 0x35, 0x13,
0x65, 0x11, 0x20, 0xc5, 0x92, 0x30, 0x0c, 0x06,
0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03,
0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
0x05, 0x00, 0x03, 0x41, 0x00, 0x85, 0x36, 0x40,
0x73, 0xc1, 0xbb, 0x1a, 0xda, 0xd4, 0x59, 0x9f,
0x2d, 0xa2, 0x70, 0x31, 0x46, 0x74, 0xec, 0x83,
0x6e, 0xa8, 0xc8, 0x3c, 0x51, 0xaf, 0x39, 0xac,
0xec, 0x40, 0xbc, 0xe8, 0x22, 0x46, 0x1d, 0x99,
0xd6, 0x46, 0x2a, 0x24, 0xd4, 0x8b, 0x05, 0x08,
0x4b, 0xfb, 0x35, 0x11, 0x6e, 0x92, 0xbb, 0x77,
0xba, 0xe4, 0x12, 0xbb, 0xf4, 0xc8, 0x5e, 0x9c,
0x81, 0xa8, 0x97, 0x60, 0x4c, 0x16, 0x03, 0x01,
0x00, 0x8b, 0x0c, 0x00, 0x00, 0x87, 0x03, 0x00,
0x17, 0x41, 0x04, 0x1c, 0x8f, 0x9c, 0x6d, 0xe7,
0xab, 0x3e, 0xf8, 0x0a, 0x5d, 0xe1, 0x86, 0xb4,
0xe2, 0x8e, 0xb2, 0x1c, 0x3b, 0xd9, 0xb6, 0x08,
0x80, 0x58, 0x21, 0xe9, 0x0e, 0xc6, 0x66, 0x67,
0x97, 0xcb, 0xb9, 0x92, 0x07, 0x00, 0xc4, 0xe5,
0xec, 0x5f, 0xb4, 0xe2, 0x20, 0xa9, 0xc9, 0x62,
0xd0, 0x98, 0xd5, 0xe3, 0x53, 0xff, 0xd0, 0x0a,
0x6e, 0x29, 0x69, 0x39, 0x2a, 0x4b, 0x5c, 0xd8,
0x6c, 0xf5, 0xfe, 0x00, 0x40, 0x35, 0xa7, 0x26,
0x2e, 0xc2, 0x48, 0x93, 0x32, 0xf7, 0x7d, 0x0f,
0x0d, 0x77, 0x56, 0x9a, 0x85, 0x0c, 0xa6, 0x74,
0x06, 0xb8, 0x3d, 0x90, 0x56, 0x12, 0x63, 0xff,
0x00, 0x5e, 0x0f, 0xf7, 0x24, 0xf7, 0xdb, 0x48,
0x71, 0xe9, 0x2e, 0x03, 0xd3, 0xfa, 0x3a, 0xae,
0xa0, 0xc1, 0x77, 0x3c, 0x4c, 0x59, 0xce, 0x33,
0x1a, 0xd2, 0x47, 0x83, 0xfa, 0xea, 0xd8, 0x1e,
0x06, 0xe7, 0x7d, 0xa0, 0x9b, 0x16, 0x03, 0x01,
0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
},
{
0x16, 0x03, 0x01, 0x00, 0x46, 0x10, 0x00, 0x00,
@ -359,34 +359,50 @@ var ecdheAESClientScript = [][]byte{
0xe2, 0x32, 0x42, 0xe9, 0x58, 0xb6, 0xd7, 0x49,
0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b,
0xdc, 0x5a, 0x89, 0x14, 0x03, 0x01, 0x00, 0x01,
0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0x9a, 0xaa,
0xca, 0x5b, 0x57, 0xae, 0x34, 0x92, 0x80, 0x45,
0x7f, 0xe6, 0xf9, 0x09, 0x19, 0xd0, 0xf0, 0x1e,
0x4b, 0xc3, 0xda, 0x71, 0xce, 0x34, 0x33, 0x56,
0x9f, 0x20, 0x9f, 0xf9, 0xa8, 0x62, 0x6c, 0x38,
0x1b, 0x41, 0xf5, 0x54, 0xf2, 0x79, 0x42, 0x6c,
0xb5, 0x0e, 0xe7, 0xe1, 0xbc, 0x54,
0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0xd9, 0xa7,
0x80, 0x56, 0x3f, 0xa3, 0x8f, 0x96, 0x72, 0x4e,
0x4e, 0x6e, 0x23, 0x41, 0x8f, 0xda, 0x91, 0xb2,
0x9e, 0x63, 0x23, 0x82, 0x64, 0xcd, 0x07, 0x24,
0xd3, 0x40, 0x20, 0x22, 0x4c, 0xe3, 0xff, 0x38,
0xbb, 0x43, 0x9d, 0x57, 0x11, 0xd5, 0x46, 0xa5,
0x05, 0x29, 0x92, 0x02, 0xce, 0xdf,
},
{
0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
0x01, 0x00, 0x30, 0x62, 0x82, 0x41, 0x75, 0x2b,
0xee, 0x0f, 0xdc, 0x6c, 0x48, 0x5a, 0x63, 0xd6,
0xcb, 0x0a, 0xfd, 0x0a, 0x0e, 0xde, 0x8b, 0x41,
0x19, 0x0c, 0x13, 0x6b, 0x12, 0xd1, 0xc2, 0x53,
0xeb, 0x1e, 0xf3, 0x7a, 0xbf, 0x23, 0xc5, 0xa6,
0x81, 0xa1, 0xdb, 0xab, 0x2f, 0x2c, 0xbc, 0x35,
0x96, 0x72, 0x83,
0x01, 0x00, 0x90, 0xe7, 0xba, 0x0e, 0xb1, 0xda,
0x92, 0xb5, 0x77, 0x56, 0x38, 0xa6, 0x22, 0xc1,
0x72, 0xeb, 0x8a, 0x68, 0x09, 0xb6, 0x74, 0xad,
0xb3, 0x4a, 0xf2, 0xdd, 0x09, 0x9b, 0xc9, 0x4f,
0x84, 0x73, 0x8b, 0xd6, 0x97, 0x50, 0x23, 0x1c,
0xa0, 0xc2, 0x0c, 0x25, 0x18, 0xdd, 0x5e, 0x15,
0x4d, 0xd9, 0xef, 0x4f, 0x6a, 0x43, 0x61, 0x9c,
0x95, 0xde, 0x3c, 0x66, 0xc4, 0xc1, 0x33, 0x56,
0xdd, 0x2f, 0x90, 0xaf, 0x68, 0x5c, 0x9c, 0xa4,
0x90, 0x6d, 0xbf, 0x51, 0x1d, 0x68, 0xcb, 0x81,
0x77, 0x52, 0xa0, 0x93, 0x2a, 0xf8, 0xc7, 0x61,
0x87, 0x76, 0xca, 0x93, 0x9e, 0xd6, 0xee, 0x6f,
0x3f, 0xeb, 0x7d, 0x06, 0xdd, 0x73, 0x4e, 0x27,
0x16, 0x63, 0x92, 0xe4, 0xb2, 0x3f, 0x91, 0x23,
0x21, 0x97, 0x90, 0xce, 0x53, 0xb8, 0xb0, 0x9d,
0xbd, 0xbd, 0x33, 0x84, 0xad, 0x6b, 0x2e, 0x7b,
0xf5, 0xeb, 0x1d, 0x64, 0x37, 0x2e, 0x29, 0x4e,
0xb0, 0x93, 0xdb, 0x92, 0xc7, 0xaa, 0x94, 0xa5,
0x3b, 0x64, 0xd0,
},
{
0x17, 0x03, 0x01, 0x00, 0x20, 0xaf, 0x5d, 0x35,
0x57, 0x10, 0x60, 0xb3, 0x25, 0x7c, 0x26, 0x0f,
0xf3, 0x5e, 0xb3, 0x0d, 0xad, 0x14, 0x53, 0xcc,
0x0c, 0x08, 0xd9, 0xa2, 0x67, 0xab, 0xf4, 0x03,
0x17, 0x20, 0xf1, 0x7e, 0xca, 0x15, 0x03, 0x01,
0x00, 0x20, 0x30, 0xd0, 0xc1, 0xfb, 0x5f, 0xa6,
0x1b, 0xb4, 0x48, 0xc2, 0x0b, 0x98, 0xa8, 0x88,
0x7a, 0xba, 0xdf, 0x36, 0x06, 0xd8, 0xcc, 0xe9,
0x34, 0xdd, 0x64, 0xc8, 0x73, 0xc5, 0xa2, 0x34,
0x64, 0xb7,
0x17, 0x03, 0x01, 0x00, 0x20, 0x11, 0xd8, 0x6b,
0x3c, 0xf6, 0xbe, 0xf4, 0x54, 0x87, 0xec, 0x75,
0x0c, 0x44, 0xdb, 0x92, 0xfc, 0xde, 0x7e, 0x0f,
0x9f, 0x87, 0x87, 0x9c, 0x03, 0xd5, 0x07, 0x84,
0xe0, 0x3a, 0xf8, 0xae, 0x14, 0x17, 0x03, 0x01,
0x00, 0x20, 0xba, 0x54, 0xef, 0x5b, 0xce, 0xfd,
0x47, 0x76, 0x6d, 0xa1, 0x8b, 0xfd, 0x48, 0xde,
0x6e, 0x26, 0xc1, 0x0c, 0x9d, 0x54, 0xbf, 0x98,
0xf6, 0x1c, 0x80, 0xb9, 0xca, 0x93, 0x81, 0x0a,
0x2e, 0x06, 0x15, 0x03, 0x01, 0x00, 0x20, 0x93,
0x3e, 0x38, 0x17, 0xc9, 0x0a, 0xc3, 0xea, 0xd3,
0x92, 0x75, 0xa6, 0x53, 0x37, 0x4d, 0x74, 0x94,
0xbe, 0x01, 0xdc, 0x5c, 0x5a, 0x0f, 0x09, 0xf6,
0x57, 0x33, 0xc3, 0xbc, 0x3f, 0x7a, 0x4d,
},
}

View File

@ -550,33 +550,99 @@ var rc4ServerScript = [][]byte{
var des3ServerScript = [][]byte{
{
0x16, 0x03, 0x01, 0x00, 0x54, 0x01, 0x00, 0x00,
0x50, 0x03, 0x01, 0x50, 0x77, 0x3d, 0xe3, 0x8e,
0x48, 0xe6, 0xbd, 0x6d, 0x72, 0x8a, 0x1a, 0x11,
0xb0, 0x8a, 0x7e, 0xff, 0x29, 0x07, 0xa8, 0x91,
0xbc, 0xea, 0x1e, 0x3e, 0x62, 0xc9, 0x8e, 0x72,
0x26, 0xd3, 0xca, 0x00, 0x00, 0x28, 0x00, 0x39,
0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13,
0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f,
0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01,
0x00,
0x16, 0x03, 0x00, 0x00, 0xc5, 0x01, 0x00, 0x00,
0xc1, 0x03, 0x03, 0x50, 0xae, 0x5d, 0x38, 0xec,
0xaa, 0x2f, 0x41, 0xf9, 0xd2, 0x7b, 0xa1, 0xfd,
0x0f, 0xff, 0x4e, 0x54, 0x0e, 0x15, 0x57, 0xaf,
0x2c, 0x91, 0xb5, 0x35, 0x5b, 0x2e, 0xb0, 0xec,
0x20, 0xe5, 0xd2, 0x00, 0x00, 0x50, 0xc0, 0x09,
0xc0, 0x23, 0xc0, 0x2b, 0xc0, 0x0a, 0xc0, 0x24,
0xc0, 0x2c, 0xc0, 0x08, 0xc0, 0x13, 0xc0, 0x27,
0xc0, 0x2f, 0xc0, 0x14, 0xc0, 0x30, 0xc0, 0x12,
0x00, 0x33, 0x00, 0x67, 0x00, 0x45, 0x00, 0x9e,
0x00, 0x39, 0x00, 0x6b, 0x00, 0x88, 0x00, 0x16,
0x00, 0x32, 0x00, 0x40, 0x00, 0x44, 0x00, 0xa2,
0x00, 0x38, 0x00, 0x6a, 0x00, 0x87, 0x00, 0x13,
0x00, 0x66, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x41,
0x00, 0x9c, 0x00, 0x35, 0x00, 0x3d, 0x00, 0x84,
0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x01, 0x00,
0x00, 0x48, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00,
0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00,
0x00, 0x23, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c,
0x00, 0x0a, 0x00, 0x13, 0x00, 0x15, 0x00, 0x17,
0x00, 0x18, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x02,
0x01, 0x00, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1a,
0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x05, 0x01,
0x05, 0x03, 0x06, 0x01, 0x06, 0x03, 0x03, 0x01,
0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02,
0x02, 0x03,
},
{
0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x16,
0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00,
0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
@ -585,163 +651,207 @@ var des3ServerScript = [][]byte{
0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e,
0x00, 0x00, 0x00,
0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00,
0x00,
},
{
0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
0x82, 0x00, 0x80, 0x33, 0x52, 0xe2, 0xd6, 0x79,
0xf8, 0xe6, 0xd4, 0xe2, 0x08, 0xb0, 0x73, 0x36,
0xa7, 0x61, 0x72, 0x19, 0xfb, 0xd1, 0x1f, 0xf5,
0xbc, 0x7c, 0x84, 0xdd, 0xed, 0x99, 0xd7, 0x5e,
0x3d, 0x11, 0xc3, 0x19, 0xb0, 0x7f, 0x10, 0x94,
0x72, 0x64, 0xf3, 0x2c, 0x3f, 0x8d, 0x73, 0x39,
0x9e, 0xca, 0x2e, 0x09, 0xbd, 0xb7, 0x8d, 0x4c,
0x5b, 0x58, 0xff, 0x4f, 0x53, 0xa9, 0xd4, 0x7c,
0x34, 0xe0, 0xaa, 0xa8, 0x14, 0xc0, 0x14, 0x25,
0x0b, 0xaa, 0x55, 0xab, 0x10, 0x34, 0x45, 0x72,
0xe8, 0x26, 0x6f, 0xf5, 0xbb, 0x3a, 0xfa, 0xd8,
0x4f, 0x70, 0xe1, 0xc1, 0xb6, 0x11, 0x1e, 0xd1,
0xe0, 0x0b, 0xa1, 0x3a, 0xdc, 0x94, 0x89, 0x7f,
0x88, 0x5e, 0x5a, 0xf1, 0x0c, 0x98, 0xe2, 0xab,
0x0e, 0x3a, 0xa8, 0x2f, 0xbb, 0xc5, 0x02, 0x07,
0x15, 0x5e, 0x46, 0x82, 0x54, 0x9c, 0x09, 0xea,
0xb9, 0x56, 0xf7, 0x14, 0x03, 0x01, 0x00, 0x01,
0x01, 0x16, 0x03, 0x01, 0x00, 0x28, 0xb9, 0xbf,
0x9a, 0xb8, 0xe4, 0x14, 0x6b, 0xc6, 0xf0, 0x27,
0xb7, 0xdb, 0xb2, 0xbc, 0x16, 0xd1, 0x3c, 0x0b,
0xc1, 0xe6, 0x1c, 0xa1, 0x29, 0xc7, 0x37, 0xe6,
0x56, 0x1d, 0x16, 0xb5, 0xa8, 0x0d, 0x4d, 0xdb,
0x9d, 0xf8, 0xb2, 0x6a, 0x90, 0x96,
0x82, 0x00, 0x80, 0x51, 0x04, 0xf1, 0x7a, 0xbf,
0xe8, 0xa5, 0x86, 0x09, 0xa7, 0xf3, 0xcc, 0x93,
0x00, 0x10, 0x5b, 0xb8, 0xc1, 0x51, 0x0d, 0x5b,
0xcd, 0xed, 0x26, 0x01, 0x69, 0x73, 0xf4, 0x05,
0x8a, 0x6a, 0xc3, 0xb1, 0x9e, 0x84, 0x4e, 0x39,
0xcf, 0x5e, 0x55, 0xa9, 0x70, 0x19, 0x96, 0x91,
0xcd, 0x2c, 0x78, 0x3c, 0xa2, 0x6d, 0xb0, 0x49,
0x86, 0xf6, 0xd1, 0x3a, 0xde, 0x00, 0x4b, 0xa6,
0x25, 0xbf, 0x85, 0x39, 0xce, 0xb1, 0xcf, 0xbc,
0x16, 0xc7, 0x66, 0xac, 0xf8, 0xd2, 0x3b, 0xd1,
0xcc, 0x16, 0xac, 0x63, 0x3c, 0xbe, 0xd9, 0xb6,
0x6a, 0xe4, 0x13, 0x8a, 0xf4, 0x56, 0x2f, 0x92,
0x54, 0xd8, 0xf0, 0x84, 0x01, 0x32, 0x1a, 0xa9,
0x2d, 0xaf, 0x82, 0x0e, 0x00, 0xfa, 0x07, 0x88,
0xd9, 0x87, 0xe7, 0xdc, 0x9e, 0xe9, 0x72, 0x49,
0xb8, 0xfa, 0x8c, 0x7b, 0x07, 0x0b, 0x03, 0x7c,
0x10, 0x8c, 0x8a, 0x14, 0x03, 0x01, 0x00, 0x01,
0x01, 0x16, 0x03, 0x01, 0x00, 0xa8, 0x61, 0xa4,
0xf4, 0x5f, 0x8a, 0x1f, 0x5c, 0x92, 0x3f, 0x8c,
0xdb, 0xd6, 0x10, 0xcd, 0x9e, 0xe7, 0xf0, 0xc4,
0x3c, 0xb6, 0x1c, 0x9a, 0x56, 0x73, 0x7f, 0xa6,
0x14, 0x24, 0xcb, 0x96, 0x1f, 0xe0, 0xaf, 0xcd,
0x3c, 0x66, 0x43, 0xb7, 0x37, 0x65, 0x34, 0x47,
0xf8, 0x43, 0xf1, 0xcc, 0x15, 0xb8, 0xdc, 0x35,
0xe0, 0xa4, 0x2d, 0x78, 0x94, 0xe0, 0x02, 0xf3,
0x76, 0x46, 0xf7, 0x9b, 0x8d, 0x0d, 0x5d, 0x0b,
0xd3, 0xdd, 0x9a, 0x9e, 0x62, 0x2e, 0xc5, 0x98,
0x75, 0x63, 0x0c, 0xbf, 0x8e, 0x49, 0x33, 0x23,
0x7c, 0x00, 0xcf, 0xfb, 0xcf, 0xba, 0x0f, 0x41,
0x39, 0x89, 0xb9, 0xcc, 0x59, 0xd0, 0x2b, 0xb6,
0xec, 0x04, 0xe2, 0xc0, 0x52, 0xc7, 0xcf, 0x71,
0x47, 0xff, 0x70, 0x7e, 0xa9, 0xbd, 0x1c, 0xdd,
0x17, 0xa5, 0x6c, 0xb7, 0x10, 0x4f, 0x42, 0x18,
0x37, 0x69, 0xa9, 0xd2, 0xb3, 0x18, 0x84, 0x92,
0xa7, 0x47, 0x21, 0xf6, 0x95, 0x63, 0x29, 0xd6,
0xa5, 0xb6, 0xda, 0x65, 0x67, 0x69, 0xc4, 0x26,
0xac, 0x8b, 0x08, 0x58, 0xdd, 0x3c, 0x31, 0x20,
0xd5, 0x0c, 0x88, 0x72, 0x18, 0x16, 0x88, 0x1e,
0x4a, 0x0f, 0xe1, 0xcf, 0x95, 0x24,
},
{
0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
0x01, 0x00, 0x28, 0x5d, 0xc9, 0xad, 0xcf, 0xf8,
0x37, 0x05, 0xec, 0x5e, 0xb2, 0x77, 0xb3, 0x1a,
0x91, 0x75, 0x1d, 0x8d, 0xdd, 0x1a, 0xff, 0xb6,
0xca, 0xf7, 0x59, 0x04, 0xb2, 0x11, 0x0a, 0x25,
0x7e, 0xc5, 0x7d, 0xba, 0x8a, 0x50, 0xcc, 0xe9,
0x89, 0xa0, 0x91, 0x17, 0x03, 0x01, 0x00, 0x28,
0x30, 0x68, 0x28, 0x1e, 0x75, 0x82, 0x04, 0xe7,
0xd3, 0x3b, 0xb1, 0x17, 0x32, 0x10, 0x7f, 0xae,
0x77, 0xeb, 0xf1, 0x46, 0xcc, 0xe5, 0xe0, 0xbe,
0x07, 0x37, 0x0d, 0x84, 0x54, 0xa1, 0x88, 0xac,
0xe5, 0x06, 0x7b, 0xee, 0xe6, 0xa1, 0xee, 0xb0,
0x15, 0x03, 0x01, 0x00, 0x18, 0x73, 0xa9, 0xf8,
0x5a, 0xd4, 0xfc, 0xd9, 0xa9, 0x82, 0x97, 0x50,
0x14, 0x76, 0x6c, 0x27, 0x9f, 0xa2, 0xf1, 0x52,
0xa0, 0xe3, 0xbd, 0xcb, 0xd3,
0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00,
0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
0xe8, 0x4b, 0xde, 0xef, 0xba, 0x3e, 0x18, 0x1c,
0x1e, 0x5e, 0xbc, 0x87, 0xf1, 0x87, 0x8d, 0x72,
0xe3, 0xbe, 0x0f, 0xdf, 0xfd, 0xd0, 0xb2, 0x89,
0xf8, 0x05, 0x9a, 0x52, 0x47, 0x77, 0x9e, 0xe8,
0xb1, 0x1d, 0x18, 0xed, 0x6a, 0x4b, 0x63, 0x1d,
0xf1, 0x62, 0xd2, 0x65, 0x21, 0x26, 0x73, 0xd4,
0x35, 0x5b, 0x95, 0x89, 0x12, 0x59, 0x23, 0x8c,
0xc3, 0xfc, 0xf9, 0x4d, 0x21, 0x79, 0xa0, 0xbd,
0xff, 0x33, 0xa2, 0x3d, 0x0b, 0x6f, 0x89, 0xc9,
0x23, 0xe4, 0xe7, 0x9f, 0x1d, 0x98, 0xf6, 0xed,
0x02, 0x8d, 0xac, 0x1a, 0xf9, 0xcb, 0xa5, 0x14,
0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
0x00, 0x28, 0x91, 0x56, 0x80, 0xe2, 0x6d, 0x51,
0x88, 0x03, 0xf8, 0x49, 0xe6, 0x6a, 0x5a, 0xfb,
0x2f, 0x0b, 0xb5, 0xa1, 0x0d, 0x63, 0x83, 0xae,
0xb9, 0xbc, 0x05, 0xf0, 0x81, 0x00, 0x61, 0x83,
0x38, 0xda, 0x14, 0xf6, 0xea, 0xd8, 0x78, 0x65,
0xc7, 0x26, 0x17, 0x03, 0x01, 0x00, 0x18, 0x81,
0x30, 0x8b, 0x22, 0x5a, 0xd3, 0x7f, 0xc8, 0xf2,
0x8a, 0x6b, 0xa3, 0xba, 0x4d, 0xe7, 0x6e, 0xd2,
0xfd, 0xbf, 0xf2, 0xc5, 0x28, 0xa0, 0x62, 0x17,
0x03, 0x01, 0x00, 0x28, 0x17, 0x83, 0x3c, 0x78,
0x18, 0xfa, 0x8d, 0x58, 0x5c, 0xaa, 0x05, 0x7d,
0x67, 0x96, 0x11, 0x60, 0x11, 0xc0, 0x1e, 0x0d,
0x6a, 0x6e, 0x5f, 0x1d, 0x98, 0x4b, 0xff, 0x82,
0xee, 0x21, 0x06, 0x29, 0xd3, 0x8b, 0x80, 0x78,
0x39, 0x05, 0x34, 0x9b, 0x15, 0x03, 0x01, 0x00,
0x18, 0xa9, 0x38, 0x18, 0x4f, 0x9d, 0x84, 0x75,
0x88, 0x53, 0xd6, 0x85, 0xc2, 0x15, 0x4b, 0xe3,
0xe3, 0x35, 0x9a, 0x74, 0xc9, 0x3e, 0x13, 0xc1,
0x8c,
},
}
var aesServerScript = [][]byte{
{
0x16, 0x03, 0x02, 0x00, 0x7f, 0x01, 0x00, 0x00,
0x7b, 0x03, 0x02, 0x4d, 0x08, 0x2d, 0x0b, 0xb3,
0x57, 0x85, 0x71, 0x4b, 0xfb, 0x34, 0xab, 0x16,
0xd4, 0x92, 0x50, 0x81, 0x16, 0x95, 0x11, 0x28,
0x1a, 0xcb, 0xff, 0x09, 0x4d, 0x23, 0xa6, 0xfe,
0x2e, 0xbb, 0x78, 0x00, 0x00, 0x34, 0x00, 0x33,
0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16,
0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87,
0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91,
0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41,
0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05,
0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b,
0x00, 0x8a, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x09,
0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f,
0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0xff,
0x01, 0x00, 0x01, 0x00,
0x16, 0x03, 0x00, 0x00, 0xc5, 0x01, 0x00, 0x00,
0xc1, 0x03, 0x03, 0x50, 0xae, 0x5c, 0xe9, 0x5e,
0x31, 0x93, 0x82, 0xa5, 0x6f, 0x51, 0x82, 0xc8,
0x55, 0x4f, 0x1f, 0x2e, 0x90, 0x98, 0x81, 0x13,
0x27, 0x80, 0x68, 0xb4, 0x2d, 0xba, 0x3a, 0x76,
0xd8, 0xd7, 0x2c, 0x00, 0x00, 0x50, 0xc0, 0x09,
0xc0, 0x23, 0xc0, 0x2b, 0xc0, 0x0a, 0xc0, 0x24,
0xc0, 0x2c, 0xc0, 0x08, 0xc0, 0x13, 0xc0, 0x27,
0xc0, 0x2f, 0xc0, 0x14, 0xc0, 0x30, 0xc0, 0x12,
0x00, 0x33, 0x00, 0x67, 0x00, 0x45, 0x00, 0x9e,
0x00, 0x39, 0x00, 0x6b, 0x00, 0x88, 0x00, 0x16,
0x00, 0x32, 0x00, 0x40, 0x00, 0x44, 0x00, 0xa2,
0x00, 0x38, 0x00, 0x6a, 0x00, 0x87, 0x00, 0x13,
0x00, 0x66, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x41,
0x00, 0x9c, 0x00, 0x35, 0x00, 0x3d, 0x00, 0x84,
0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x01, 0x00,
0x00, 0x48, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00,
0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00,
0x00, 0x23, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c,
0x00, 0x0a, 0x00, 0x13, 0x00, 0x15, 0x00, 0x17,
0x00, 0x18, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x02,
0x01, 0x00, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1a,
0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x05, 0x01,
0x05, 0x03, 0x06, 0x01, 0x06, 0x03, 0x03, 0x01,
0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02,
0x02, 0x03,
},
{
0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x16,
0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00,
0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
@ -750,120 +860,126 @@ var aesServerScript = [][]byte{
0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e,
0x00, 0x00, 0x00,
0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00,
0x00,
},
{
0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
0x82, 0x00, 0x80, 0x71, 0x9c, 0xe7, 0x23, 0xfc,
0xb9, 0x19, 0x29, 0x82, 0xbf, 0xef, 0x08, 0xf7,
0x99, 0x36, 0xc3, 0x4c, 0x6f, 0x05, 0xd2, 0x8b,
0x62, 0x2b, 0x19, 0x9b, 0x7f, 0xc0, 0xcc, 0x48,
0x30, 0x5f, 0xcd, 0xc3, 0x70, 0x55, 0x53, 0x73,
0xfa, 0x79, 0x74, 0xf3, 0xa3, 0x76, 0x9f, 0xa1,
0x7f, 0x98, 0xc2, 0xc0, 0xe3, 0xc5, 0xa0, 0x31,
0x2f, 0xa6, 0xe8, 0x1e, 0x61, 0x46, 0xb3, 0x9b,
0x4b, 0x16, 0xf1, 0x2d, 0xc7, 0x63, 0x7f, 0x79,
0x22, 0x30, 0xd1, 0xf2, 0xfc, 0x77, 0x98, 0x0a,
0x16, 0x11, 0x63, 0x71, 0x7f, 0x70, 0xef, 0x16,
0xbb, 0x39, 0x87, 0x34, 0xac, 0x49, 0xbd, 0x07,
0x67, 0xcb, 0x9c, 0xcc, 0xde, 0xef, 0xb1, 0xe0,
0xdb, 0x01, 0xb5, 0x35, 0xa9, 0xb3, 0x10, 0x0c,
0x4b, 0xee, 0xb3, 0x4e, 0xfd, 0xbe, 0x15, 0x27,
0xf0, 0x46, 0xb2, 0x38, 0xba, 0x5f, 0xcc, 0x89,
0xec, 0x29, 0x82, 0x14, 0x03, 0x01, 0x00, 0x01,
0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0x3c, 0xfb,
0xa4, 0x12, 0xcb, 0x00, 0xf9, 0x57, 0x7e, 0x9b,
0xc9, 0xdc, 0x0c, 0xba, 0x9a, 0x81, 0x62, 0xfb,
0x26, 0x13, 0x53, 0xfe, 0xaa, 0xcc, 0x82, 0xbb,
0xb6, 0x67, 0x7f, 0x39, 0xbe, 0x4d, 0xbb, 0xc0,
0x6c, 0x24, 0x31, 0x83, 0xa5, 0x50, 0x3a, 0x75,
0x32, 0x64, 0xb5, 0xdb, 0xbe, 0x0a,
0x82, 0x00, 0x80, 0x51, 0x2e, 0xec, 0x0d, 0x86,
0xf3, 0x9f, 0xf2, 0x77, 0x04, 0x27, 0x2b, 0x0e,
0x9c, 0xab, 0x35, 0x84, 0x65, 0xff, 0x36, 0xef,
0xc0, 0x08, 0xc9, 0x1d, 0x9f, 0x29, 0xae, 0x8d,
0xc5, 0x66, 0x81, 0x31, 0x92, 0x5e, 0x3d, 0xac,
0xaa, 0x37, 0x28, 0x2c, 0x06, 0x91, 0xa6, 0xc2,
0xd0, 0x83, 0x34, 0x24, 0x1c, 0x88, 0xfc, 0x0a,
0xcf, 0xbf, 0xc2, 0x94, 0xe2, 0xed, 0xa7, 0x6a,
0xa8, 0x8d, 0x3d, 0xf7, 0x06, 0x7d, 0x69, 0xf8,
0x0d, 0xb2, 0xf7, 0xe4, 0x45, 0xcb, 0x0a, 0x25,
0xcb, 0xb2, 0x2e, 0x38, 0x9a, 0x84, 0x75, 0xe8,
0xe1, 0x42, 0x39, 0xa2, 0x18, 0x0e, 0x48, 0xca,
0x33, 0x16, 0x4e, 0xf6, 0x2f, 0xec, 0x07, 0xe7,
0x57, 0xe1, 0x20, 0x40, 0x40, 0x6d, 0x4e, 0x29,
0x04, 0x1a, 0x8c, 0x99, 0xfb, 0x19, 0x3c, 0xaa,
0x75, 0x64, 0xd3, 0xa6, 0xe6, 0xed, 0x3f, 0x5a,
0xd2, 0xc9, 0x80, 0x14, 0x03, 0x01, 0x00, 0x01,
0x01, 0x16, 0x03, 0x01, 0x01, 0x10, 0xe9, 0x9e,
0x06, 0x92, 0x18, 0xbf, 0x5e, 0xaf, 0x33, 0xc1,
0xbf, 0x0e, 0x12, 0x07, 0x48, 0x4f, 0x6b, 0x6c,
0xf5, 0x23, 0x5e, 0x87, 0xa7, 0xd3, 0x50, 0x79,
0x38, 0xdc, 0xe0, 0x49, 0xd3, 0x81, 0x21, 0x12,
0xd0, 0x3d, 0x9a, 0xfb, 0x83, 0xc1, 0x8b, 0xfc,
0x14, 0xd5, 0xd5, 0xa7, 0xa3, 0x34, 0x14, 0x71,
0xbe, 0xea, 0x37, 0x18, 0x12, 0x7f, 0x41, 0xfb,
0xc5, 0x51, 0x17, 0x9d, 0x96, 0x58, 0x14, 0xfb,
0x4f, 0xd7, 0xd3, 0x15, 0x0f, 0xec, 0x5a, 0x0d,
0x35, 0xbb, 0x3c, 0x81, 0x5b, 0x3f, 0xdf, 0x52,
0xa4, 0x4c, 0xcd, 0x13, 0xe1, 0x10, 0x37, 0x34,
0xbf, 0xb4, 0x80, 0x1e, 0x8d, 0xe2, 0xc3, 0x7a,
0x0f, 0x7b, 0x7d, 0x23, 0xeb, 0xd0, 0x99, 0x69,
0xad, 0x0a, 0x2d, 0xb3, 0x6c, 0xd6, 0x80, 0x11,
0x7f, 0x6c, 0xed, 0x1b, 0xcd, 0x08, 0x22, 0x56,
0x90, 0x0e, 0xa4, 0xc3, 0x29, 0x33, 0x96, 0x30,
0x34, 0x94, 0xa1, 0xeb, 0x9c, 0x1b, 0x5a, 0xd1,
0x03, 0x61, 0xf9, 0xdd, 0xf3, 0x64, 0x8a, 0xfd,
0x5f, 0x44, 0xdb, 0x2e, 0xa7, 0xfd, 0xe1, 0x1a,
0x66, 0xc5, 0x01, 0x9c, 0xc7, 0xd1, 0xc4, 0xd3,
0xea, 0x14, 0x3c, 0xed, 0x74, 0xbb, 0x1b, 0x97,
0x8f, 0xf1, 0x29, 0x39, 0x33, 0x92, 0x93, 0x4e,
0xf5, 0x87, 0x91, 0x61, 0x65, 0x8d, 0x27, 0x8d,
0x76, 0xc1, 0xfa, 0x6a, 0x99, 0x80, 0xb1, 0x9b,
0x29, 0x53, 0xce, 0x3e, 0xb6, 0x9a, 0xce, 0x3c,
0x19, 0x5e, 0x48, 0x83, 0xaa, 0xa7, 0x66, 0x98,
0x59, 0xf4, 0xbb, 0xf2, 0xbc, 0xd9, 0xc5, 0x9a,
0xc8, 0x2c, 0x63, 0x58, 0xd5, 0xd4, 0xbc, 0x03,
0xa9, 0x06, 0xa9, 0x80, 0x0d, 0xb3, 0x46, 0x2d,
0xe3, 0xc6, 0xaf, 0x1a, 0x39, 0x18, 0x7e, 0x1e,
0x83, 0x80, 0x46, 0x11, 0xd2, 0x13, 0x9f, 0xda,
0xfc, 0x2d, 0x42, 0xaa, 0x5a, 0x1d, 0x4c, 0x31,
0xe5, 0x58, 0x78, 0x5e, 0xe2, 0x04, 0xd6, 0x23,
0x7f, 0x3f, 0x06, 0xc0, 0x54, 0xf8,
},
{
0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
0x01, 0x00, 0x30, 0x43, 0x24, 0x42, 0x55, 0x08,
0xe4, 0xc2, 0x15, 0xc9, 0xdb, 0x71, 0x69, 0xee,
0x09, 0xc5, 0x1c, 0xfd, 0x46, 0x10, 0xa0, 0x68,
0x21, 0xf2, 0x48, 0xac, 0x6c, 0xc0, 0x2b, 0x62,
0x07, 0x8f, 0x48, 0x33, 0x0a, 0x6b, 0x62, 0x28,
0x2e, 0x2c, 0xad, 0xcb, 0x34, 0x85, 0xca, 0x2e,
0xcd, 0x84, 0xf0,
0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00,
0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
0xe8, 0x4b, 0xfb, 0xef, 0xba, 0xed, 0xc5, 0x36,
0xc8, 0x5a, 0x41, 0x3f, 0x05, 0xfa, 0xfe, 0x48,
0xc3, 0x91, 0x12, 0x8b, 0xe8, 0x32, 0x6a, 0x9f,
0xdc, 0x97, 0xe2, 0x77, 0xb9, 0x96, 0x2d, 0xd4,
0xe5, 0xbd, 0xa1, 0xfd, 0x94, 0xbb, 0x74, 0x63,
0xb1, 0x0c, 0x38, 0xbc, 0x6f, 0x69, 0xaf, 0xa3,
0x46, 0x9c, 0x96, 0x41, 0xde, 0x59, 0x23, 0xff,
0x15, 0x6b, 0x3a, 0xef, 0x91, 0x6d, 0x92, 0x44,
0xdc, 0x72, 0x1f, 0x40, 0x3d, 0xb5, 0x34, 0x8f,
0x2a, 0xac, 0x21, 0x69, 0x05, 0x6f, 0xb2, 0x60,
0x32, 0x5d, 0x3d, 0x97, 0xb4, 0x24, 0x99, 0x14,
0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
0x00, 0x30, 0x68, 0x27, 0x97, 0xca, 0x63, 0x09,
0x22, 0xed, 0x0e, 0x61, 0x7c, 0x76, 0x31, 0x9c,
0xbe, 0x27, 0xc9, 0xe6, 0x09, 0xc3, 0xc3, 0xc2,
0xf4, 0xa2, 0x32, 0xba, 0x7c, 0xf2, 0x0f, 0xb8,
0x3d, 0xcb, 0xe2, 0x4c, 0xc0, 0x7d, 0x8e, 0x5b,
0x5a, 0xed, 0x05, 0x5c, 0x15, 0x96, 0x69, 0xc2,
0x6f, 0x5f, 0x17, 0x03, 0x01, 0x00, 0x20, 0x5a,
0xfe, 0x0b, 0xe1, 0x6f, 0xa8, 0x54, 0x19, 0x78,
0xca, 0xba, 0x2e, 0x1e, 0x2e, 0xe1, 0x5d, 0x17,
0xe5, 0x97, 0x05, 0x2c, 0x08, 0x0c, 0xff, 0xa8,
0x59, 0xa9, 0xde, 0x5e, 0x21, 0x34, 0x04, 0x17,
0x03, 0x01, 0x00, 0x30, 0x86, 0xb1, 0x3f, 0x88,
0x43, 0xf0, 0x07, 0xee, 0xa8, 0xf4, 0xbc, 0xe7,
0x5f, 0xc6, 0x8c, 0x86, 0x4c, 0xca, 0x70, 0x88,
0xcc, 0x6a, 0xb4, 0x3d, 0x40, 0xe8, 0x54, 0x89,
0x19, 0x43, 0x1f, 0x76, 0xe2, 0xac, 0xb2, 0x5b,
0x92, 0xf8, 0x57, 0x39, 0x2a, 0xc3, 0x6d, 0x13,
0x45, 0xfa, 0x36, 0x9e, 0x15, 0x03, 0x01, 0x00,
0x20, 0x6d, 0xed, 0x7b, 0x59, 0x28, 0x2a, 0x27,
0x04, 0x15, 0x07, 0x4e, 0xeb, 0x13, 0x00, 0xe3,
0x3a, 0x3f, 0xf8, 0xaa, 0x2b, 0x3b, 0x1a, 0x8c,
0x12, 0xd6, 0x4c, 0xec, 0x2a, 0xaf, 0x33, 0x60,
0xaf,
},
}

View File

@ -155,7 +155,7 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error)
err = errors.New("crypto/tls: failed to parse key PEM data")
return
}
if strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") {
if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") {
break
}
}

View File

@ -33,6 +33,19 @@ D2lWusoe2/nEqfDVVWGWlyJ7yOmqaVm/iNUN9B2N2g==
-----END RSA PRIVATE KEY-----
`
// keyPEM is the same as rsaKeyPEM, but declares itself as just
// "PRIVATE KEY", not "RSA PRIVATE KEY". http://golang.org/issue/4477
var keyPEM = `-----BEGIN PRIVATE KEY-----
MIIBOwIBAAJBANLJhPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wo
k/4xIA+ui35/MmNartNuC+BdZ1tMuVCPFZcCAwEAAQJAEJ2N+zsR0Xn8/Q6twa4G
6OB1M1WO+k+ztnX/1SvNeWu8D6GImtupLTYgjZcHufykj09jiHmjHx8u8ZZB/o1N
MQIhAPW+eyZo7ay3lMz1V01WVjNKK9QSn1MJlb06h/LuYv9FAiEA25WPedKgVyCW
SmUwbPw8fnTcpqDWE3yTO3vKcebqMSsCIBF3UmVue8YU3jybC3NxuXq3wNm34R8T
xVLHwDXh/6NJAiEAl2oHGGLz64BuAfjKrqwz7qMYr9HCLIe/YsoWq/olzScCIQDi
D2lWusoe2/nEqfDVVWGWlyJ7yOmqaVm/iNUN9B2N2g==
-----END PRIVATE KEY-----
`
var ecdsaCertPEM = `-----BEGIN CERTIFICATE-----
MIIB/jCCAWICCQDscdUxw16XFDAJBgcqhkjOPQQBMEUxCzAJBgNVBAYTAkFVMRMw
EQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0
@ -62,21 +75,22 @@ kohxS/xfFg/TEwRSSws+roJr4JFKpO2t3/be5OdqmQ==
var keyPairTests = []struct {
algo string
cert *string
key *string
cert string
key string
}{
{"ECDSA", &ecdsaCertPEM, &ecdsaKeyPEM},
{"RSA", &rsaCertPEM, &rsaKeyPEM},
{"ECDSA", ecdsaCertPEM, ecdsaKeyPEM},
{"RSA", rsaCertPEM, rsaKeyPEM},
{"RSA-untyped", rsaCertPEM, keyPEM}, // golang.org/issue/4477
}
func TestX509KeyPair(t *testing.T) {
var pem []byte
for _, test := range keyPairTests {
pem = []byte(*test.cert + *test.key)
pem = []byte(test.cert + test.key)
if _, err := X509KeyPair(pem, pem); err != nil {
t.Errorf("Failed to load %s cert followed by %s key: %s", test.algo, test.algo, err)
}
pem = []byte(*test.key + *test.cert)
pem = []byte(test.key + test.cert)
if _, err := X509KeyPair(pem, pem); err != nil {
t.Errorf("Failed to load %s key followed by %s cert: %s", test.algo, test.algo, err)
}

View File

@ -184,7 +184,7 @@ func Read(r io.Reader, order ByteOrder, data interface{}) error {
// values, or a pointer to such data.
// Bytes written to w are encoded using the specified byte order
// and read from successive fields of the data.
// When writing structs, zero values are are written for fields
// When writing structs, zero values are written for fields
// with blank (_) field names.
func Write(w io.Writer, order ByteOrder, data interface{}) error {
// Fast path for basic types.

View File

@ -22,7 +22,7 @@ import (
//
// If UseCRLF is true, the Writer ends each record with \r\n instead of \n.
type Writer struct {
Comma rune // Field delimiter (set to to ',' by NewWriter)
Comma rune // Field delimiter (set to ',' by NewWriter)
UseCRLF bool // True to use \r\n as the line terminator
w *bufio.Writer
}

View File

@ -328,7 +328,7 @@ reserved).
01 // Add 1 to get field number 0: field[1].name
01 // 1 byte
59 // structType.field[1].name = "Y"
01 // Add 1 to get field number 1: field[0].id
01 // Add 1 to get field number 1: field[1].id
04 // struct.Type.field[1].typeId is 2 (signed int).
00 // End of structType.field[1]; end of structType.field.
00 // end of wireType.structType structure

View File

@ -50,6 +50,7 @@ func BenchmarkEndToEndByteBuffer(b *testing.B) {
}
func TestCountEncodeMallocs(t *testing.T) {
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
var buf bytes.Buffer
enc := NewEncoder(&buf)
bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
@ -69,6 +70,7 @@ func TestCountEncodeMallocs(t *testing.T) {
}
func TestCountDecodeMallocs(t *testing.T) {
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
var buf bytes.Buffer
enc := NewEncoder(&buf)
bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}

View File

@ -45,7 +45,7 @@ const (
// - a field with tag "name,attr" becomes an attribute with
// the given name in the XML element.
// - a field with tag ",attr" becomes an attribute with the
// field name in the in the XML element.
// 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 ",innerxml" is written verbatim, not subject

View File

@ -0,0 +1,89 @@
// 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.
// Package cookiejar implements an RFC 6265-compliant http.CookieJar.
//
// TODO: example code to create a memory-backed cookie jar with the default
// public suffix list.
package cookiejar
import (
"net/http"
"net/url"
)
// PublicSuffixList provides the public suffix of a domain. For example:
// - the public suffix of "example.com" is "com",
// - the public suffix of "foo1.foo2.foo3.co.uk" is "co.uk", and
// - the public suffix of "bar.pvt.k12.wy.us" is "pvt.k12.wy.us".
//
// Implementations of PublicSuffixList must be safe for concurrent use by
// multiple goroutines.
//
// An implementation that always returns "" is valid and may be useful for
// testing but it is not secure: it means that the HTTP server for foo.com can
// set a cookie for bar.com.
type PublicSuffixList interface {
// PublicSuffix returns the public suffix of domain.
//
// TODO: specify which of the caller and callee is responsible for IP
// addresses, for leading and trailing dots, for case sensitivity, and
// for IDN/Punycode.
PublicSuffix(domain string) string
// String returns a description of the source of this public suffix list.
// A Jar will store its PublicSuffixList's description in its storage,
// and update the stored cookies if its list has a different description
// than the stored list. The description will typically contain something
// like a time stamp or version number.
String() string
}
// Options are the options for creating a new Jar.
type Options struct {
// Storage is the cookie jar storage. It may not be nil.
Storage Storage
// PublicSuffixList is the public suffix list that determines whether an
// HTTP server can set a cookie for a domain. It may not be nil.
PublicSuffixList PublicSuffixList
// TODO: ErrorFunc for handling storage errors?
}
// Jar implements the http.CookieJar interface from the net/http package.
type Jar struct {
storage Storage
psList PublicSuffixList
}
// New returns a new cookie jar.
func New(o *Options) *Jar {
return &Jar{
storage: o.Storage,
psList: o.PublicSuffixList,
}
}
// TODO(nigeltao): how do we reject HttpOnly cookies? Do we post-process the
// return value from Jar.Cookies?
//
// HttpOnly cookies are those for regular HTTP(S) requests but should not be
// visible from JavaScript. The HttpOnly bit mitigates XSS attacks; it's not
// for HTTP vs HTTPS vs FTP transports.
// Cookies implements the Cookies method of the http.CookieJar interface.
//
// It returns an empty slice if the URL's scheme is not HTTP or HTTPS.
func (j *Jar) Cookies(u *url.URL) []*http.Cookie {
// TODO.
return nil
}
// SetCookies implements the SetCookies method of the http.CookieJar interface.
//
// It does nothing if the URL's scheme is not HTTP or HTTPS.
func (j *Jar) SetCookies(u *url.URL, cookies []*http.Cookie) {
// TODO.
}

View File

@ -0,0 +1,101 @@
// 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.
package cookiejar
import (
"time"
)
// Storage is a Jar's storage. It is a multi-map, mapping keys to one or more
// entries. Each entry consists of a subkey, creation time, last access time,
// and some arbitrary data.
//
// The Add and Delete methods have undefined behavior if the key is invalid.
// A valid key must use only bytes in the character class [a-z0-9.-] and
// must have at least one non-. byte. Note that this excludes any key
// containing a capital ASCII letter as well as the empty string.
type Storage interface {
// A client must call Lock before calling other methods and must call
// Unlock when finished. Between the calls to Lock and Unlock, a client
// can assume that other clients are not modifying the Storage.
Lock()
Unlock()
// Add adds entries to the storage. Each entry's Subkey and Data must
// both be non-empty.
//
// If the Storage already contains an entry with the same key and
// subkey then the new entry is stored with the creation time of the
// old entry, and the old entry is deleted.
//
// Adding entries may cause other entries to be deleted, to maintain an
// implementation-specific storage constraint.
Add(key string, entries ...Entry) error
// Delete deletes all entries for the given key.
Delete(key string) error
// Entries calls f for each entry stored for that key. If f returns a
// non-nil error then the iteration stops and Entries returns that
// error. Iteration is not guaranteed to be in any particular order.
//
// If f returns an Update action then that stored entry's LastAccess
// time will be set to the time that f returned. If f returns a Delete
// action then that entry will be deleted from the Storage.
//
// f may call a Storage's Add and Delete methods; those modifications
// will not affect the list of entries visited in this call to Entries.
Entries(key string, f func(entry Entry) (Action, time.Time, error)) error
// Keys calls f for each key stored. f will not be called on a key with
// zero entries. If f returns a non-nil error then the iteration stops
// and Keys returns that error. Iteration is not guaranteed to be in any
// particular order.
//
// f may call a Storage's Add, Delete and Entries methods; those
// modifications will not affect the list of keys visited in this call
// to Keys.
Keys(f func(key string) error) error
}
// Entry is an entry in a Storage.
type Entry struct {
Subkey string
Data string
Creation time.Time
LastAccess time.Time
}
// Action is an action returned by the function passed to Entries.
type Action int
const (
// Pass means to take no further action with an Entry.
Pass Action = iota
// Update means to update the LastAccess time of an Entry.
Update
// Delete means to delete an Entry.
Delete
)
// ValidStorageKey returns whether the given key is valid for a Storage.
func ValidStorageKey(key string) bool {
hasNonDot := false
for i := 0; i < len(key); i++ {
switch c := key[i]; {
case 'a' <= c && c <= 'z':
fallthrough
case '0' <= c && c <= '9':
fallthrough
case c == '-':
hasNonDot = true
case c == '.':
// No-op.
default:
return false
}
}
return hasNonDot
}

View File

@ -0,0 +1,48 @@
// 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.
package cookiejar
import (
"testing"
)
var validStorageKeyTests = map[string]bool{
"": false,
".": false,
"..": false,
"/": false,
"EXAMPLE.com": false,
"\n": false,
"\r": false,
"\r\n": false,
"\x00": false,
"back\\slash": false,
"co:lon": false,
"com,ma": false,
"semi;colon": false,
"sl/ash": false,
"sp ace": false,
"under_score": false,
"π": false,
"-": true,
".dot": true,
".dot.": true,
".metadata": true,
".x..y..z...": true,
"dot.": true,
"example.com": true,
"foo": true,
"hy-phen": true,
"xn--bcher-kva.ch": true,
}
func TestValidStorageKey(t *testing.T) {
for key, want := range validStorageKeyTests {
if got := ValidStorageKey(key); got != want {
t.Errorf("%q: got %v, want %v", key, got, want)
}
}
}

View File

@ -5,20 +5,38 @@
package main
import (
"go/build"
"path/filepath"
"runtime"
"strings"
"testing"
)
func runTest(t *testing.T, path, pkg string) {
func runTest(t *testing.T, path string) {
exitCode = 0
*pkgName = pkg
*recursive = false
if pkg == "" {
*recursive = false
if suffix := ".go"; strings.HasSuffix(path, suffix) {
// single file
path = filepath.Join(runtime.GOROOT(), "src/pkg", path)
path, file := filepath.Split(path)
*pkgName = file[:len(file)-len(suffix)]
processFiles([]string{path}, true)
} else {
processDirectory(path)
// package directory
// TODO(gri) gotype should use the build package instead
pkg, err := build.Import(path, "", 0)
if err != nil {
t.Errorf("build.Import error for path = %s: %s", path, err)
return
}
// TODO(gri) there ought to be a more direct way using the build package...
files := make([]string, len(pkg.GoFiles))
for i, file := range pkg.GoFiles {
files[i] = filepath.Join(pkg.Dir, file)
}
*pkgName = pkg.Name
processFiles(files, true)
}
if exitCode != 0 {
@ -26,26 +44,167 @@ func runTest(t *testing.T, path, pkg string) {
}
}
var tests = []struct {
path string
pkg string
}{
var tests = []string{
// individual files
{"testdata/test1.go", ""},
"exp/gotype/testdata/test1.go",
// directories
{filepath.Join(runtime.GOROOT(), "src/pkg/go/ast"), "ast"},
{filepath.Join(runtime.GOROOT(), "src/pkg/go/build"), "build"},
{filepath.Join(runtime.GOROOT(), "src/pkg/go/doc"), "doc"},
{filepath.Join(runtime.GOROOT(), "src/pkg/go/parser"), "parser"},
{filepath.Join(runtime.GOROOT(), "src/pkg/go/printer"), "printer"},
{filepath.Join(runtime.GOROOT(), "src/pkg/go/scanner"), "scanner"},
{filepath.Join(runtime.GOROOT(), "src/pkg/go/token"), "token"},
{filepath.Join(runtime.GOROOT(), "src/pkg/exp/types"), "types"},
// Note: packages that don't typecheck yet are commented out
// "archive/tar", // investigate
"archive/zip",
"bufio",
"bytes",
"compress/bzip2",
"compress/flate",
"compress/gzip",
"compress/lzw",
"compress/zlib",
"container/heap",
"container/list",
"container/ring",
"crypto",
"crypto/aes",
"crypto/cipher",
"crypto/des",
"crypto/dsa",
"crypto/ecdsa",
"crypto/elliptic",
"crypto/hmac",
"crypto/md5",
"crypto/rand",
"crypto/rc4",
// "crypto/rsa", // investigate (GOARCH=386)
"crypto/sha1",
"crypto/sha256",
"crypto/sha512",
"crypto/subtle",
"crypto/tls",
// "crypto/x509", // investigate
"crypto/x509/pkix",
"database/sql",
"database/sql/driver",
"debug/dwarf",
"debug/elf",
"debug/gosym",
"debug/macho",
"debug/pe",
"encoding/ascii85",
"encoding/asn1",
"encoding/base32",
"encoding/base64",
// "encoding/binary", // complex() doesn't work yet
"encoding/csv",
// "encoding/gob", // complex() doesn't work yet
"encoding/hex",
"encoding/json",
"encoding/pem",
"encoding/xml",
"errors",
"expvar",
"flag",
"fmt",
"exp/types",
"exp/gotype",
"go/ast",
"go/build",
// "go/doc", // variadic parameters don't work yet fully
"go/format",
"go/parser",
"go/printer",
"go/scanner",
"go/token",
"hash/adler32",
// "hash/crc32", // investigate
"hash/crc64",
"hash/fnv",
"image",
"image/color",
"image/draw",
"image/gif",
"image/jpeg",
"image/png",
"index/suffixarray",
"io",
// "io/ioutil", // investigate
"log",
"log/syslog",
"math",
// "math/big", // investigate
// "math/cmplx", // complex doesn't work yet
"math/rand",
"mime",
"mime/multipart",
// "net", // depends on C files
"net/http",
"net/http/cgi",
// "net/http/fcgi", // investigate
"net/http/httptest",
"net/http/httputil",
// "net/http/pprof", // investigate
"net/mail",
// "net/rpc", // investigate
"net/rpc/jsonrpc",
"net/smtp",
"net/textproto",
"net/url",
// "path", // variadic parameters don't work yet fully
// "path/filepath", // investigate
// "reflect", // investigate
"regexp",
"regexp/syntax",
"runtime",
// "runtime/cgo", // import "C"
"runtime/debug",
"runtime/pprof",
"sort",
// "strconv", // investigate
"strings",
// "sync", // platform-specific files
// "sync/atomic", // platform-specific files
// "syscall", // platform-specific files
"testing",
"testing/iotest",
"testing/quick",
"text/scanner",
"text/tabwriter",
// "text/template", // variadic parameters don't work yet fully
// "text/template/parse", // variadic parameters don't work yet fully
// "time", // platform-specific files
"unicode",
"unicode/utf16",
"unicode/utf8",
}
func Test(t *testing.T) {
for _, test := range tests {
runTest(t, test.path, test.pkg)
runTest(t, test)
}
}

View 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.
package p
package test1
func _() {
// the scope of a local type declaration starts immediately after the type name

View File

@ -450,7 +450,7 @@ func (c *Collator) keyFromElems(buf *Buffer, ws []colElem) {
}
// Derive the quaternary weights from the options and other levels.
// Note that we represent maxQuaternary as 0xFF. The first byte of the
// representation of a a primary weight is always smaller than 0xFF,
// representation of a primary weight is always smaller than 0xFF,
// so using this single byte value will compare correctly.
if Quaternary <= c.Strength && c.Alternate >= AltShifted {
if c.Alternate == AltShiftTrimmed {

View File

@ -36,7 +36,7 @@ type checker struct {
//
// TODO(gri) This is very similar to the declare function in go/parser; it
// is only used to associate methods with their respective receiver base types.
// In a future version, it might be simpler and cleaner do to all the resolution
// In a future version, it might be simpler and cleaner to do all the resolution
// in the type-checking phase. It would simplify the parser, AST, and also
// reduce some amount of code duplication.
//
@ -188,14 +188,13 @@ func (check *checker) object(obj *ast.Object, cycleOk bool) {
case ast.Fun:
fdecl := obj.Decl.(*ast.FuncDecl)
if fdecl.Recv != nil {
// This will ensure that the method base type is
// type-checked
check.collectFields(token.FUNC, fdecl.Recv, true)
}
check.collectParams(fdecl.Recv, false) // ensure method base is type-checked
ftyp := check.typ(fdecl.Type, cycleOk).(*Signature)
obj.Type = ftyp
check.function(ftyp, fdecl.Body)
// functions implemented elsewhere (say in assembly) have no body
if fdecl.Body != nil {
check.function(ftyp, fdecl.Body)
}
default:
panic("unreachable")
@ -355,12 +354,19 @@ func check(fset *token.FileSet, pkg *ast.Package, errh func(token.Pos, string),
check.mapf = f
check.initexprs = make(map[*ast.ValueSpec][]ast.Expr)
// handle bailouts
// handle panics
defer func() {
if p := recover(); p != nil {
_ = p.(bailout) // re-panic if not a bailout
switch p := recover().(type) {
case nil:
// normal return - nothing to do
case bailout:
// early exit
err = check.firsterr
default:
// unexpected panic: don't crash clients
// panic(p) // enable for debugging
err = fmt.Errorf("types.check internal error: %v", p)
}
err = check.firsterr
}()
// determine missing constant initialization expressions

View File

@ -49,6 +49,7 @@ var tests = []struct {
{"decls0", []string{"testdata/decls0.src"}},
{"decls1", []string{"testdata/decls1.src"}},
{"decls2", []string{"testdata/decls2a.src", "testdata/decls2b.src"}},
{"decls3", []string{"testdata/decls3.src"}},
{"const0", []string{"testdata/const0.src"}},
{"expr0", []string{"testdata/expr0.src"}},
{"expr1", []string{"testdata/expr1.src"}},

View File

@ -278,7 +278,7 @@ func isRepresentableConst(x interface{}, as BasicKind) bool {
return as == String || as == UntypedString
case nilType:
return as == UntypedNil
return as == UntypedNil || as == UnsafePointer
default:
unreachable()

View File

@ -12,75 +12,131 @@ import (
"strconv"
)
// TODO(gri)
// TODO(gri) Cleanups
// - don't print error messages referring to invalid types (they are likely spurious errors)
// - simplify invalid handling: maybe just use Typ[Invalid] as marker, get rid of invalid Mode for values?
// - rethink error handling: should all callers check if x.mode == valid after making a call?
// - at the moment, iota is passed around almost everywhere - in many places we know it cannot be used
func (check *checker) tag(field *ast.Field) string {
if t := field.Tag; t != nil {
assert(t.Kind == token.STRING)
if tag, err := strconv.Unquote(t.Value); err == nil {
return tag
// TODO(gri) API issues
// - clients need access to result type information (tuples)
// - clients need access to constant values
// - clients need access to built-in type information
// TODO(gri) Bugs
// - expression hints are (correctly) used untyped for composite literal components, but also
// in possibly overlapping use as hints for shift expressions - investigate
func (check *checker) collectParams(list *ast.FieldList, variadicOk bool) (params ObjList, isVariadic bool) {
if list == nil {
return
}
var last *ast.Object
for i, field := range list.List {
ftype := field.Type
if t, _ := ftype.(*ast.Ellipsis); t != nil {
ftype = t.Elt
if variadicOk && i == len(list.List)-1 {
isVariadic = true
} else {
check.invalidAST(field.Pos(), "... not permitted")
// ok to continue
}
}
// the parser ensures that f.Tag is nil and we don't
// care if a constructed AST contains a non-nil tag
typ := check.typ(ftype, true)
if len(field.Names) > 0 {
// named parameter
for _, name := range field.Names {
obj := name.Obj
obj.Type = typ
params = append(params, obj)
last = obj
}
} else {
// anonymous parameter
obj := ast.NewObj(ast.Var, "")
obj.Type = typ
params = append(params, obj)
last = obj
}
}
// For a variadic function, change the last parameter's object type
// from T to []T (this is the type used inside the function), but
// keep a copy of the object with the original type T in the params
// list (this is the externally visible type).
if isVariadic {
// if isVariadic is set, last must exist and len(params) > 0
copy := *last
last.Type = &Slice{Elt: last.Type.(Type)}
params[len(params)-1] = &copy
}
return
}
func (check *checker) collectMethods(list *ast.FieldList) (methods ObjList) {
if list == nil {
return
}
for _, f := range list.List {
typ := check.typ(f.Type, len(f.Names) > 0) // cycles are not ok for embedded interfaces
// the parser ensures that f.Tag is nil and we don't
// care if a constructed AST contains a non-nil tag
if len(f.Names) > 0 {
// methods (the parser ensures that there's only one
// and we don't care if a constructed AST has more)
if _, ok := typ.(*Signature); !ok {
check.invalidAST(f.Type.Pos(), "%s is not a method signature", typ)
continue
}
for _, name := range f.Names {
obj := name.Obj
obj.Type = typ
methods = append(methods, obj)
}
} else {
// embedded interface
utyp := underlying(typ)
if ityp, ok := utyp.(*Interface); ok {
methods = append(methods, ityp.Methods...)
} else if utyp != Typ[Invalid] {
// if utyp is invalid, don't complain (the root cause was reported before)
check.errorf(f.Type.Pos(), "%s is not an interface type", typ)
}
}
}
// check for double declarations
methods.Sort()
prev := ""
for _, obj := range methods {
if obj.Name == prev {
check.errorf(list.Pos(), "multiple methods named %s", prev)
return // keep multiple entries, lookup will only return the first entry
}
}
return
}
func (check *checker) tag(t *ast.BasicLit) string {
if t != nil {
if t.Kind == token.STRING {
if val, err := strconv.Unquote(t.Value); err == nil {
return val
}
}
check.invalidAST(t.Pos(), "incorrect tag syntax: %q", t.Value)
}
return ""
}
// collectFields collects interface methods (tok = token.INTERFACE), and function arguments/results (tok = token.FUNC).
func (check *checker) collectFields(tok token.Token, list *ast.FieldList, cycleOk bool) (fields ObjList, tags []string, isVariadic bool) {
if list != nil {
for _, field := range list.List {
ftype := field.Type
if t, ok := ftype.(*ast.Ellipsis); ok {
ftype = t.Elt
isVariadic = true
}
typ := check.typ(ftype, cycleOk)
tag := check.tag(field)
if len(field.Names) > 0 {
// named fields
for _, name := range field.Names {
obj := name.Obj
obj.Type = typ
fields = append(fields, obj)
if tok == token.STRUCT {
tags = append(tags, tag)
}
}
} else {
// anonymous field
switch tok {
case token.FUNC:
obj := ast.NewObj(ast.Var, "")
obj.Type = typ
fields = append(fields, obj)
case token.INTERFACE:
utyp := underlying(typ)
if typ, ok := utyp.(*Interface); ok {
// TODO(gri) This is not good enough. Check for double declarations!
fields = append(fields, typ.Methods...)
} else if utyp != Typ[Invalid] {
// if utyp is invalid, don't complain (the root cause was reported before)
check.errorf(ftype.Pos(), "interface contains embedded non-interface type")
}
default:
panic("unreachable")
}
}
}
}
return
}
func (check *checker) collectStructFields(list *ast.FieldList, cycleOk bool) (fields []*StructField) {
func (check *checker) collectFields(list *ast.FieldList, cycleOk bool) (fields []*StructField) {
if list == nil {
return
}
for _, f := range list.List {
typ := check.typ(f.Type, cycleOk)
tag := check.tag(f)
tag := check.tag(f.Tag)
if len(f.Names) > 0 {
// named fields
for _, name := range f.Names {
@ -90,9 +146,9 @@ func (check *checker) collectStructFields(list *ast.FieldList, cycleOk bool) (fi
// anonymous field
switch t := deref(typ).(type) {
case *Basic:
fields = append(fields, &StructField{t.Name, t, tag, true})
fields = append(fields, &StructField{t.Name, typ, tag, true})
case *NamedType:
fields = append(fields, &StructField{t.Obj.Name, t, tag, true})
fields = append(fields, &StructField{t.Obj.Name, typ, tag, true})
default:
if typ != Typ[Invalid] {
check.invalidAST(f.Type.Pos(), "anonymous field type %s must be named", typ)
@ -115,9 +171,6 @@ var unaryOpPredicates = opPredicates{
func (check *checker) op(m opPredicates, x *operand, op token.Token) bool {
if pred := m[op]; pred != nil {
if !pred(x.typ) {
// TODO(gri) better error message for <-x where x is a send-only channel
// (<- is defined but not permitted). Special-case here or
// handle higher up.
check.invalidOp(x.pos(), "operator %s not defined for %s", op, x)
return false
}
@ -173,7 +226,7 @@ func (check *checker) unary(x *operand, op token.Token) {
}
// Typed constants must be representable in
// their type after each constant operation.
check.isRepresentable(x, x.typ.(*Basic))
check.isRepresentable(x, underlying(x.typ).(*Basic))
return
}
@ -424,34 +477,107 @@ func (check *checker) binary(x, y *operand, op token.Token, hint Type) {
}
// index checks an index expression for validity. If length >= 0, it is the upper
// bound for the index. The result is a valid integer constant, or nil.
// bound for the index. The result is a valid index >= 0, or a negative value.
//
func (check *checker) index(index ast.Expr, length int64, iota int) interface{} {
func (check *checker) index(index ast.Expr, length int64, iota int) int64 {
var x operand
check.expr(&x, index, nil, iota)
if !x.isInteger() {
check.errorf(x.pos(), "index %s must be integer", &x)
return nil
return -1
}
if x.mode != constant {
return nil // we cannot check more
return -1 // we cannot check more
}
// x.mode == constant and the index value must be >= 0
if isNegConst(x.val) {
// The spec doesn't require int64 indices, but perhaps it should.
i, ok := x.val.(int64)
if !ok {
check.errorf(x.pos(), "stupid index %s", &x)
return -1
}
if i < 0 {
check.errorf(x.pos(), "index %s must not be negative", &x)
return nil
return -1
}
// x.val >= 0
if length >= 0 && compareConst(x.val, length, token.GEQ) {
if length >= 0 && i >= length {
check.errorf(x.pos(), "index %s is out of bounds (>= %d)", &x, length)
return nil
return -1
}
return x.val
return i
}
func (check *checker) callRecord(x *operand) {
// indexElts checks the elements (elts) of an array or slice composite literal
// against the literals element type (typ), and the element indices against
// the literal length if known (length >= 0). It returns the length of the
// literal (maximum index value + 1).
//
func (check *checker) indexedElts(elts []ast.Expr, typ Type, length int64, iota int) int64 {
visited := make(map[int64]bool, len(elts))
var index, max int64
for _, e := range elts {
// determine and check index
validIndex := false
eval := e
if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
if i := check.index(kv.Key, length, iota); i >= 0 {
index = i
validIndex = true
}
eval = kv.Value
} else if length >= 0 && index >= length {
check.errorf(e.Pos(), "index %d is out of bounds (>= %d)", index, length)
} else {
validIndex = true
}
// if we have a valid index, check for duplicate entries
if validIndex {
if visited[index] {
check.errorf(e.Pos(), "duplicate index %d in array or slice literal", index)
}
visited[index] = true
}
index++
if index > max {
max = index
}
// check element against composite literal element type
var x operand
check.expr(&x, eval, typ, iota)
if !x.isAssignable(typ) {
check.errorf(x.pos(), "cannot use %s as %s value in array or slice literal", &x, typ)
}
}
return max
}
func (check *checker) argument(sig *Signature, i int, arg ast.Expr) {
var par *ast.Object
if n := len(sig.Params); i < n {
par = sig.Params[i]
} else if sig.IsVariadic {
par = sig.Params[n-1]
} else {
check.errorf(arg.Pos(), "too many arguments")
return
}
// TODO(gri) deal with ... last argument
var z, x operand
z.mode = variable
z.expr = nil // TODO(gri) can we do better here?
z.typ = par.Type.(Type) // TODO(gri) should become something like checkObj(&z, ...) eventually
check.expr(&x, arg, z.typ, -1)
if x.mode == invalid {
return // ignore this argument
}
check.assignOperand(&z, &x)
}
func (check *checker) recordType(x *operand) {
if x.mode != invalid {
check.mapf(x.expr, x.typ)
}
@ -470,7 +596,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
}
if check.mapf != nil {
defer check.callRecord(x)
defer check.recordType(x)
}
switch e := e.(type) {
@ -527,7 +653,10 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
x.typ = obj.Type.(Type)
case *ast.Ellipsis:
unimplemented()
// ellipses are handled explictly where they are legal
// (array composite literals and parameter lists)
check.errorf(e.Pos(), "invalid use of '...'")
goto Error
case *ast.BasicLit:
x.setConst(e.Kind, e.Value)
@ -537,27 +666,146 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
}
case *ast.FuncLit:
x.mode = value
x.typ = check.typ(e.Type, false)
// TODO(gri) handle errors (e.g. x.typ is not a *Signature)
check.function(x.typ.(*Signature), e.Body)
if typ, ok := check.typ(e.Type, false).(*Signature); ok {
x.mode = value
x.typ = typ
check.function(typ, e.Body)
} else {
check.invalidAST(e.Pos(), "invalid function literal %s", e)
goto Error
}
case *ast.CompositeLit:
// TODO(gri)
// - determine element type if nil
// - deal with map elements
var typ Type
typ := hint
openArray := false
if e.Type != nil {
// TODO(gri) Fix this - just to get going for now
typ = check.typ(e.Type, false)
// [...]T array types may only appear with composite literals.
// Check for them here so we don't have to handle ... in general.
typ = nil
if atyp, _ := e.Type.(*ast.ArrayType); atyp != nil && atyp.Len != nil {
if ellip, _ := atyp.Len.(*ast.Ellipsis); ellip != nil && ellip.Elt == nil {
// We have an "open" [...]T array type.
// Create a new ArrayType with unknown length (-1)
// and finish setting it up after analyzing the literal.
typ = &Array{Len: -1, Elt: check.typ(atyp.Elt, cycleOk)}
openArray = true
}
}
if typ == nil {
typ = check.typ(e.Type, false)
}
}
for _, e := range e.Elts {
var x operand
check.expr(&x, e, hint, iota)
// TODO(gri) check assignment compatibility to element type
if typ == nil {
check.errorf(e.Pos(), "missing type in composite literal")
goto Error
}
// TODO(gri) this is not correct - leave for now to get going
x.mode = variable
switch utyp := underlying(deref(typ)).(type) {
case *Struct:
if len(e.Elts) == 0 {
break
}
fields := utyp.Fields
if _, ok := e.Elts[0].(*ast.KeyValueExpr); ok {
// all elements must have keys
visited := make([]bool, len(fields))
for _, e := range e.Elts {
kv, _ := e.(*ast.KeyValueExpr)
if kv == nil {
check.errorf(e.Pos(), "mixture of field:value and value elements in struct literal")
continue
}
key, _ := kv.Key.(*ast.Ident)
if key == nil {
check.errorf(kv.Pos(), "invalid field name %s in struct literal", kv.Key)
continue
}
i := utyp.fieldIndex(key.Name)
if i < 0 {
check.errorf(kv.Pos(), "unknown field %s in struct literal", key.Name)
continue
}
// 0 <= i < len(fields)
if visited[i] {
check.errorf(kv.Pos(), "duplicate field name %s in struct literal", key.Name)
continue
}
visited[i] = true
check.expr(x, kv.Value, nil, iota)
etyp := fields[i].Type
if !x.isAssignable(etyp) {
check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp)
continue
}
}
} else {
// no element must have a key
for i, e := range e.Elts {
if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
check.errorf(kv.Pos(), "mixture of field:value and value elements in struct literal")
continue
}
check.expr(x, e, nil, iota)
if i >= len(fields) {
check.errorf(x.pos(), "too many values in struct literal")
break // cannot continue
}
// i < len(fields)
etyp := fields[i].Type
if !x.isAssignable(etyp) {
check.errorf(x.pos(), "cannot use %s as an element of type %s in struct literal", x, etyp)
continue
}
}
if len(e.Elts) < len(fields) {
check.errorf(e.Rbrace, "too few values in struct literal")
// ok to continue
}
}
case *Array:
n := check.indexedElts(e.Elts, utyp.Elt, utyp.Len, iota)
// if we have an "open" [...]T array, set the length now that we know it
if openArray {
utyp.Len = n
}
case *Slice:
check.indexedElts(e.Elts, utyp.Elt, -1, iota)
case *Map:
visited := make(map[interface{}]bool, len(e.Elts))
for _, e := range e.Elts {
kv, _ := e.(*ast.KeyValueExpr)
if kv == nil {
check.errorf(e.Pos(), "missing key in map literal")
continue
}
check.expr(x, kv.Key, nil, iota)
if !x.isAssignable(utyp.Key) {
check.errorf(x.pos(), "cannot use %s as %s key in map literal", x, utyp.Key)
continue
}
if x.mode == constant {
if visited[x.val] {
check.errorf(x.pos(), "duplicate key %s in map literal", x.val)
continue
}
visited[x.val] = true
}
check.expr(x, kv.Value, utyp.Elt, iota)
if !x.isAssignable(utyp.Elt) {
check.errorf(x.pos(), "cannot use %s as %s value in map literal", x, utyp.Elt)
continue
}
}
default:
check.errorf(e.Pos(), "%s is not a valid composite literal type", typ)
goto Error
}
x.mode = variable // TODO(gri) mode is really a value - keep for now to get going
x.typ = typ
case *ast.ParenExpr:
@ -604,7 +852,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
}
mode, typ := lookupField(x.typ, sel)
if mode == invalid {
check.invalidOp(e.Pos(), "%s has no field or method %s", x, sel)
check.invalidOp(e.Pos(), "%s has no single field or method %s", x, sel)
goto Error
}
if x.mode == typexpr {
@ -617,7 +865,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
// the receiver type becomes the type of the first function
// argument of the method expression's function type
// TODO(gri) at the moment, method sets don't correctly track
// pointer vs non-pointer receivers -> typechecker is too lenient
// pointer vs non-pointer receivers => typechecker is too lenient
arg := ast.NewObj(ast.Var, "")
arg.Type = x.typ
x.mode = value
@ -659,15 +907,29 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
}
x.typ = typ.Elt
case *Pointer:
if typ, _ := underlying(typ.Base).(*Array); typ != nil {
valid = true
length = typ.Len
x.mode = variable
x.typ = typ.Elt
}
case *Slice:
valid = true
x.mode = variable
x.typ = typ.Elt
case *Map:
// TODO(gri) check index type
var key operand
check.expr(&key, e.Index, nil, iota)
if key.mode == invalid || !key.isAssignable(typ.Key) {
check.invalidOp(x.pos(), "cannot use %s as map index of type %s", &key, typ.Key)
goto Error
}
x.mode = valueok
x.typ = typ.Elt
x.expr = e
return
}
@ -698,7 +960,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
}
// a sliced string always yields a string value
// of the same type as the original string (not
// a constant) even if the string and the indexes
// a constant) even if the string and the indices
// are constant
x.mode = value
// x.typ doesn't change
@ -713,6 +975,14 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
}
x.typ = &Slice{Elt: typ.Elt}
case *Pointer:
if typ, _ := underlying(typ.Base).(*Array); typ != nil {
valid = true
length = typ.Len + 1 // +1 for slice
x.mode = variable
x.typ = &Slice{Elt: typ.Elt}
}
case *Slice:
valid = true
x.mode = variable
@ -724,33 +994,55 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
goto Error
}
var lo interface{} = zeroConst
lo := int64(0)
if e.Low != nil {
lo = check.index(e.Low, length, iota)
}
var hi interface{}
hi := int64(-1)
if e.High != nil {
hi = check.index(e.High, length, iota)
} else if length >= 0 {
hi = length
}
if lo != nil && hi != nil && compareConst(lo, hi, token.GTR) {
check.errorf(e.Low.Pos(), "inverted slice range: %v > %v", lo, hi)
if lo >= 0 && hi >= 0 && lo > hi {
check.errorf(e.Low.Pos(), "inverted slice range: %d > %d", lo, hi)
// ok to continue
}
case *ast.TypeAssertExpr:
check.expr(x, e.X, hint, iota)
if _, ok := underlying(x.typ).(*Interface); !ok {
check.invalidOp(e.X.Pos(), "non-interface type %s in type assertion", x.typ)
if x.mode == invalid {
goto Error
}
var T *Interface
if T, _ = underlying(x.typ).(*Interface); T == nil {
check.invalidOp(x.pos(), "%s is not an interface", x)
goto Error
}
// x.(type) expressions are handled explicitly in type switches
if e.Type == nil {
check.errorf(e.Pos(), "use of .(type) outside type switch")
goto Error
}
typ := check.typ(e.Type, false)
if typ == Typ[Invalid] {
goto Error
}
if method, wrongType := missingMethod(typ, T); method != nil {
var msg string
if wrongType {
msg = "%s cannot have dynamic type %s (wrong type for method %s)"
} else {
msg = "%s cannot have dynamic type %s (missing method %s)"
}
check.errorf(e.Type.Pos(), msg, x, typ, method.Name)
// ok to continue
}
// TODO(gri) some type asserts are compile-time decidable
x.mode = valueok
x.expr = e
x.typ = check.typ(e.Type, false)
x.typ = typ
case *ast.CallExpr:
check.exprOrType(x, e.Fun, nil, iota, false)
@ -760,21 +1052,11 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
check.conversion(x, e, x.typ, iota)
} else if sig, ok := underlying(x.typ).(*Signature); ok {
// check parameters
// TODO(gri) complete this
// - deal with various forms of calls
// - handle variadic calls
if len(sig.Params) == len(e.Args) {
var z, x operand
z.mode = variable
for i, arg := range e.Args {
z.expr = nil // TODO(gri) can we do better here?
z.typ = sig.Params[i].Type.(Type) // TODO(gri) should become something like checkObj(&z, ...) eventually
check.expr(&x, arg, z.typ, iota)
if x.mode == invalid {
goto Error
}
check.assignOperand(&z, &x)
}
// TODO(gri)
// - deal with single multi-valued function arguments: f(g())
// - variadic functions only partially addressed
for i, arg := range e.Args {
check.argument(sig, i, arg)
}
// determine result
@ -827,32 +1109,26 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
check.binary(x, &y, e.Op, hint)
case *ast.KeyValueExpr:
unimplemented()
// key:value expressions are handled in composite literals
check.invalidAST(e.Pos(), "no key:value expected")
goto Error
case *ast.ArrayType:
if e.Len != nil {
var n int64 = -1
if ellip, ok := e.Len.(*ast.Ellipsis); ok {
// TODO(gri) need to check somewhere that [...]T types are only used with composite literals
if ellip.Elt != nil {
check.invalidAST(ellip.Pos(), "ellipsis only expected")
// ok to continue
}
} else {
check.expr(x, e.Len, nil, 0)
if x.mode == invalid {
goto Error
}
if x.mode == constant {
if i, ok := x.val.(int64); ok && i == int64(int(i)) {
n = i
}
}
if n < 0 {
check.errorf(e.Len.Pos(), "invalid array bound %s", e.Len)
// ok to continue
n = 0
check.expr(x, e.Len, nil, iota)
if x.mode == invalid {
goto Error
}
if x.mode != constant {
if x.mode != invalid {
check.errorf(x.pos(), "array length %s must be constant", x)
}
goto Error
}
n, ok := x.val.(int64)
if !ok || n < 0 {
check.errorf(x.pos(), "invalid array length %s", x)
goto Error
}
x.typ = &Array{Len: n, Elt: check.typ(e.Elt, cycleOk)}
} else {
@ -862,19 +1138,17 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
case *ast.StructType:
x.mode = typexpr
x.typ = &Struct{Fields: check.collectStructFields(e.Fields, cycleOk)}
x.typ = &Struct{Fields: check.collectFields(e.Fields, cycleOk)}
case *ast.FuncType:
params, _, isVariadic := check.collectFields(token.FUNC, e.Params, true)
results, _, _ := check.collectFields(token.FUNC, e.Results, true)
params, isVariadic := check.collectParams(e.Params, true)
results, _ := check.collectParams(e.Results, false)
x.mode = typexpr
x.typ = &Signature{Recv: nil, Params: params, Results: results, IsVariadic: isVariadic}
case *ast.InterfaceType:
methods, _, _ := check.collectFields(token.INTERFACE, e.Methods, cycleOk)
methods.Sort()
x.mode = typexpr
x.typ = &Interface{Methods: methods}
x.typ = &Interface{Methods: check.collectMethods(e.Methods)}
case *ast.MapType:
x.mode = typexpr
@ -920,10 +1194,7 @@ func (check *checker) expr(x *operand, e ast.Expr, hint Type, iota int) {
}
}
// expr is like rawExpr but reports an error if e doesn't represents a type.
// It returns e's type, or Typ[Invalid] if an error occured.
//
func (check *checker) typ(e ast.Expr, cycleOk bool) Type {
func (check *checker) rawTyp(e ast.Expr, cycleOk, nilOk bool) Type {
var x operand
check.rawExpr(&x, e, nil, -1, cycleOk)
switch x.mode {
@ -933,8 +1204,27 @@ func (check *checker) typ(e ast.Expr, cycleOk bool) Type {
check.errorf(x.pos(), "%s used as type", &x)
case typexpr:
return x.typ
case constant:
if nilOk && x.isNil() {
return nil
}
fallthrough
default:
check.errorf(x.pos(), "%s is not a type", &x)
}
return Typ[Invalid]
}
// typOrNil is like rawExpr but reports an error if e doesn't represents a type or the predeclared value nil.
// It returns e's type, nil, or Typ[Invalid] if an error occured.
//
func (check *checker) typOrNil(e ast.Expr, cycleOk bool) Type {
return check.rawTyp(e, cycleOk, true)
}
// typ is like rawExpr but reports an error if e doesn't represents a type.
// It returns e's type, or Typ[Invalid] if an error occured.
//
func (check *checker) typ(e ast.Expr, cycleOk bool) Type {
return check.rawTyp(e, cycleOk, false)
}

View File

@ -119,21 +119,15 @@ func (x *operand) setConst(tok token.Token, lit string) {
}
}
// implements reports whether x implements interface T.
func (x *operand) implements(T *Interface) bool {
if x.mode == invalid {
return true // avoid spurious errors
}
unimplemented()
return true
}
// isNil reports whether x is the predeclared nil constant.
func (x *operand) isNil() bool {
return x.mode == constant && x.val == nilConst
}
// TODO(gri) The functions operand.isAssignable, checker.convertUntyped,
// checker.isRepresentable, and checker.assignOperand are
// overlapping in functionality. Need to simplify and clean up.
// isAssignable reports whether x is assignable to a variable of type T.
func (x *operand) isAssignable(T Type) bool {
if x.mode == invalid || T == Typ[Invalid] {
@ -157,8 +151,10 @@ func (x *operand) isAssignable(T Type) bool {
}
// T is an interface type and x implements T
if Ti, ok := Tu.(*Interface); ok && x.implements(Ti) {
return true
if Ti, ok := Tu.(*Interface); ok {
if m, _ := missingMethod(x.typ, Ti); m == nil {
return true
}
}
// x is a bidirectional channel value, T is a channel
@ -181,8 +177,18 @@ func (x *operand) isAssignable(T Type) bool {
}
// x is an untyped constant representable by a value of type T
// - this is taken care of in the assignment check
// TODO(gri) double-check - isAssignable is used elsewhere
// TODO(gri) This is borrowing from checker.convertUntyped and
// checker.isRepresentable. Need to clean up.
if isUntyped(Vu) {
switch t := Tu.(type) {
case *Basic:
return x.mode == constant && isRepresentableConst(x.val, t.Kind)
case *Interface:
return x.isNil() || len(t.Methods) == 0
case *Pointer, *Signature, *Slice, *Map, *Chan:
return x.isNil()
}
}
return false
}
@ -199,35 +205,50 @@ type lookupResult struct {
typ Type
}
// lookupFieldRecursive is similar to FieldByNameFunc in reflect/type.go
// TODO(gri): FieldByNameFunc seems more complex - what are we missing?
func lookupFieldRecursive(list []*NamedType, name string) (res lookupResult) {
// visited records the types that have been searched already
visited := make(map[Type]bool)
type embeddedType struct {
typ *NamedType
multiples bool // if set, typ is embedded multiple times at the same level
}
// lookupFieldBreadthFirst searches all types in list for a single entry (field
// or method) of the given name. If such a field is found, the result describes
// the field mode and type; otherwise the result mode is invalid.
// (This function is similar in structure to FieldByNameFunc in reflect/type.go)
//
func lookupFieldBreadthFirst(list []embeddedType, name string) (res lookupResult) {
// visited records the types that have been searched already.
visited := make(map[*NamedType]bool)
// embedded types of the next lower level
var next []*NamedType
var next []embeddedType
potentialMatch := func(mode operandMode, typ Type) bool {
if res.mode != invalid {
// name appeared multiple times at this level - annihilate
// potentialMatch is invoked every time a match is found.
potentialMatch := func(multiples bool, mode operandMode, typ Type) bool {
if multiples || res.mode != invalid {
// name appeared already at this level - annihilate
res.mode = invalid
return false
}
// first appearance of name
res.mode = mode
res.typ = typ
return true
}
// look for name in all types of this level
// Search the current level if there is any work to do and collect
// embedded types of the next lower level in the next list.
for len(list) > 0 {
// The res.mode indicates whether we have found a match already
// on this level (mode != invalid), or not (mode == invalid).
assert(res.mode == invalid)
for _, typ := range list {
// start with empty next list (don't waste underlying array)
next = next[:0]
// look for name in all types at this level
for _, e := range list {
typ := e.typ
if visited[typ] {
// We have seen this type before, at a higher level.
// That higher level shadows the lower level we are
// at now, and either we would have found or not
// found the field before. Ignore this type now.
continue
}
visited[typ] = true
@ -236,7 +257,7 @@ func lookupFieldRecursive(list []*NamedType, name string) (res lookupResult) {
if data := typ.Obj.Data; data != nil {
if obj := data.(*ast.Scope).Lookup(name); obj != nil {
assert(obj.Type != nil)
if !potentialMatch(value, obj.Type.(Type)) {
if !potentialMatch(e.multiples, value, obj.Type.(Type)) {
return // name collision
}
}
@ -244,21 +265,26 @@ func lookupFieldRecursive(list []*NamedType, name string) (res lookupResult) {
switch typ := underlying(typ).(type) {
case *Struct:
// look for a matching fieldm and collect embedded types
// look for a matching field and collect embedded types
for _, f := range typ.Fields {
if f.Name == name {
assert(f.Type != nil)
if !potentialMatch(variable, f.Type) {
if !potentialMatch(e.multiples, variable, f.Type) {
return // name collision
}
continue
}
// Collect embedded struct fields for searching the next
// lower level, but only if we have not seen a match yet.
// lower level, but only if we have not seen a match yet
// (if we have a match it is either the desired field or
// we have a name collision on the same level; in either
// case we don't need to look further).
// Embedded fields are always of the form T or *T where
// T is a named type.
// T is a named type. If typ appeared multiple times at
// this level, f.Type appears multiple times at the next
// level.
if f.IsAnonymous && res.mode == invalid {
next = append(next, deref(f.Type).(*NamedType))
next = append(next, embeddedType{deref(f.Type).(*NamedType), e.multiples})
}
}
@ -267,7 +293,7 @@ func lookupFieldRecursive(list []*NamedType, name string) (res lookupResult) {
for _, obj := range typ.Methods {
if obj.Name == name {
assert(obj.Type != nil)
if !potentialMatch(value, obj.Type.(Type)) {
if !potentialMatch(e.multiples, value, obj.Type.(Type)) {
return // name collision
}
}
@ -276,17 +302,41 @@ func lookupFieldRecursive(list []*NamedType, name string) (res lookupResult) {
}
if res.mode != invalid {
// we found a match on this level
// we found a single match on this level
return
}
// search the next level
list = append(list[:0], next...) // don't waste underlying arrays
next = next[:0]
// No match and no collision so far.
// Compute the list to search for the next level.
list = list[:0] // don't waste underlying array
for _, e := range next {
// Instead of adding the same type multiple times, look for
// it in the list and mark it as multiple if it was added
// before.
// We use a sequential search (instead of a map for next)
// because the lists tend to be small, can easily be reused,
// and explicit search appears to be faster in this case.
if alt := findType(list, e.typ); alt != nil {
alt.multiples = true
} else {
list = append(list, e)
}
}
}
return
}
func findType(list []embeddedType, typ *NamedType) *embeddedType {
for i := range list {
if p := &list[i]; p.typ == typ {
return p
}
}
return nil
}
func lookupField(typ Type, name string) (operandMode, Type) {
typ = deref(typ)
@ -301,17 +351,20 @@ func lookupField(typ Type, name string) (operandMode, Type) {
switch typ := underlying(typ).(type) {
case *Struct:
var list []*NamedType
var next []embeddedType
for _, f := range typ.Fields {
if f.Name == name {
return variable, f.Type
}
if f.IsAnonymous {
list = append(list, deref(f.Type).(*NamedType))
// Possible optimization: If the embedded type
// is a pointer to the current type we could
// ignore it.
next = append(next, embeddedType{typ: deref(f.Type).(*NamedType)})
}
}
if len(list) > 0 {
res := lookupFieldRecursive(list, name)
if len(next) > 0 {
res := lookupFieldBreadthFirst(next, name)
return res.mode, res.typ
}

View File

@ -6,6 +6,8 @@
package types
import "go/ast"
func isNamed(typ Type) bool {
if _, ok := typ.(*Basic); ok {
return ok
@ -247,3 +249,34 @@ func defaultType(typ Type) Type {
}
return typ
}
// missingMethod returns (nil, false) if typ implements T, otherwise
// it returns the first missing method required by T and whether it
// is missing or simply has the wrong type.
//
func missingMethod(typ Type, T *Interface) (method *ast.Object, wrongType bool) {
// TODO(gri): distinguish pointer and non-pointer receivers
// an interface type implements T if it has no methods with conflicting signatures
// Note: This is stronger than the current spec. Should the spec require this?
if ityp, _ := underlying(typ).(*Interface); ityp != nil {
for _, m := range T.Methods {
mode, sig := lookupField(ityp, m.Name) // TODO(gri) no need to go via lookupField
if mode != invalid && !isIdentical(sig, m.Type.(Type)) {
return m, true
}
}
return
}
// a concrete type implements T if it implements all methods of T.
for _, m := range T.Methods {
mode, sig := lookupField(typ, m.Name)
if mode == invalid {
return m, false
}
if !isIdentical(sig, m.Type.(Type)) {
return m, true
}
}
return
}

View File

@ -27,8 +27,8 @@ func (check *checker) assignOperand(z, x *operand) {
}
}
// assign1to1 typechecks a single assignment of the form lhs := rhs (if rhs != nil),
// or lhs := x (if rhs == nil). If decl is set, the lhs operand must be an identifier.
// assign1to1 typechecks a single assignment of the form lhs = rhs (if rhs != nil),
// or lhs = x (if rhs == nil). If decl is set, the lhs operand must be an identifier.
// If its type is not set, it is deduced from the type or value of x. If lhs has a
// type it is used as a hint when evaluating rhs, if present.
//
@ -226,6 +226,38 @@ func (check *checker) stmtList(list []ast.Stmt) {
}
}
func (check *checker) call(call *ast.CallExpr) {
var x operand
check.rawExpr(&x, call, nil, -1, false) // don't check if value is used
// TODO(gri) If a builtin is called, the builtin must be valid in statement context.
}
func (check *checker) multipleDefaults(list []ast.Stmt) {
var first ast.Stmt
for _, s := range list {
var d ast.Stmt
switch c := s.(type) {
case *ast.CaseClause:
if len(c.List) == 0 {
d = s
}
case *ast.CommClause:
if c.Comm == nil {
d = s
}
default:
check.invalidAST(s.Pos(), "case/communication clause expected")
}
if d != nil {
if first != nil {
check.errorf(d.Pos(), "multiple defaults (first at %s)", first.Pos())
} else {
first = d
}
}
}
}
// stmt typechecks statement s.
func (check *checker) stmt(s ast.Stmt) {
switch s := s.(type) {
@ -265,7 +297,7 @@ func (check *checker) stmt(s ast.Stmt) {
}
check.rawExpr(&x, s.X, nil, -1, false)
if x.mode == typexpr {
check.errorf(x.pos(), "%s is not an expression", x)
check.errorf(x.pos(), "%s is not an expression", &x)
}
case *ast.SendStmt:
@ -347,10 +379,10 @@ func (check *checker) stmt(s ast.Stmt) {
}
case *ast.GoStmt:
unimplemented()
check.call(s.Call)
case *ast.DeferStmt:
unimplemented()
check.call(s.Call)
case *ast.ReturnStmt:
sig := check.functypes[len(check.functypes)-1]
@ -403,31 +435,122 @@ func (check *checker) stmt(s ast.Stmt) {
x.typ = Typ[UntypedBool]
x.val = true
}
check.multipleDefaults(s.Body.List)
for _, s := range s.Body.List {
if clause, ok := s.(*ast.CaseClause); ok {
for _, expr := range clause.List {
var y operand
check.expr(&y, expr, nil, -1)
// TODO(gri) x and y must be comparable
}
check.stmtList(clause.Body)
} else {
check.errorf(s.Pos(), "invalid AST: case clause expected")
clause, _ := s.(*ast.CaseClause)
if clause == nil {
continue // error reported before
}
for _, expr := range clause.List {
var y operand
check.expr(&y, expr, nil, -1)
// TODO(gri) x and y must be comparable
}
check.stmtList(clause.Body)
}
case *ast.TypeSwitchStmt:
unimplemented()
check.optionalStmt(s.Init)
// A type switch guard must be of the form:
//
// TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
//
// The parser is checking syntactic correctness;
// remaining syntactic errors are considered AST errors here.
// TODO(gri) better factoring of error handling (invalid ASTs)
//
var lhs *ast.Object // lhs identifier object or nil
var rhs ast.Expr
switch guard := s.Assign.(type) {
case *ast.ExprStmt:
rhs = guard.X
case *ast.AssignStmt:
if len(guard.Lhs) != 1 || guard.Tok != token.DEFINE || len(guard.Rhs) != 1 {
check.invalidAST(s.Pos(), "incorrect form of type switch guard")
return
}
ident, _ := guard.Lhs[0].(*ast.Ident)
if ident == nil {
check.invalidAST(s.Pos(), "incorrect form of type switch guard")
return
}
lhs = ident.Obj
rhs = guard.Rhs[0]
default:
check.invalidAST(s.Pos(), "incorrect form of type switch guard")
return
}
// rhs must be of the form: expr.(type) and expr must be an interface
expr, _ := rhs.(*ast.TypeAssertExpr)
if expr == nil || expr.Type != nil {
check.invalidAST(s.Pos(), "incorrect form of type switch guard")
return
}
var x operand
check.expr(&x, expr.X, nil, -1)
if x.mode == invalid {
return
}
var T *Interface
if T, _ = underlying(x.typ).(*Interface); T == nil {
check.errorf(x.pos(), "%s is not an interface", &x)
return
}
check.multipleDefaults(s.Body.List)
for _, s := range s.Body.List {
clause, _ := s.(*ast.CaseClause)
if clause == nil {
continue // error reported before
}
// Check each type in this type switch case.
var typ Type
for _, expr := range clause.List {
typ = check.typOrNil(expr, false)
if typ != nil && typ != Typ[Invalid] {
if method, wrongType := missingMethod(typ, T); method != nil {
var msg string
if wrongType {
msg = "%s cannot have dynamic type %s (wrong type for method %s)"
} else {
msg = "%s cannot have dynamic type %s (missing method %s)"
}
check.errorf(expr.Pos(), msg, &x, typ, method.Name)
// ok to continue
}
}
}
// If lhs exists, set its type for each clause.
if lhs != nil {
// In clauses with a case listing exactly one type, the variable has that type;
// otherwise, the variable has the type of the expression in the TypeSwitchGuard.
if len(clause.List) != 1 || typ == nil {
typ = x.typ
}
lhs.Type = typ
}
check.stmtList(clause.Body)
}
// There is only one object (lhs) associated with a lhs identifier, but that object
// assumes different types for different clauses. Set it to nil when we are done so
// that the type cannot be used by mistake.
if lhs != nil {
lhs.Type = nil
}
case *ast.SelectStmt:
check.multipleDefaults(s.Body.List)
for _, s := range s.Body.List {
c, ok := s.(*ast.CommClause)
if !ok {
check.invalidAST(s.Pos(), "communication clause expected")
continue
clause, _ := s.(*ast.CommClause)
if clause == nil {
continue // error reported before
}
check.optionalStmt(c.Comm) // TODO(gri) check correctness of c.Comm (must be Send/RecvStmt)
check.stmtList(c.Body)
check.optionalStmt(clause.Comm) // TODO(gri) check correctness of c.Comm (must be Send/RecvStmt)
check.stmtList(clause.Body)
}
case *ast.ForStmt:
@ -443,7 +566,79 @@ func (check *checker) stmt(s ast.Stmt) {
check.stmt(s.Body)
case *ast.RangeStmt:
unimplemented()
// check expression to iterate over
decl := s.Tok == token.DEFINE
var x operand
check.expr(&x, s.X, nil, -1)
if x.mode == invalid {
// if we don't have a declaration, we can still check the loop's body
if !decl {
check.stmt(s.Body)
}
return
}
// determine key/value types
var key, val Type
switch typ := underlying(x.typ).(type) {
case *Basic:
if isString(typ) {
key = Typ[UntypedInt]
val = Typ[UntypedRune]
}
case *Array:
key = Typ[UntypedInt]
val = typ.Elt
case *Slice:
key = Typ[UntypedInt]
val = typ.Elt
case *Pointer:
if typ, _ := underlying(typ.Base).(*Array); typ != nil {
key = Typ[UntypedInt]
val = typ.Elt
}
case *Map:
key = typ.Key
val = typ.Elt
case *Chan:
key = typ.Elt
if typ.Dir&ast.RECV == 0 {
check.errorf(x.pos(), "cannot range over send-only channel %s", &x)
// ok to continue
}
if s.Value != nil {
check.errorf(s.Value.Pos(), "iteration over %s permits only one iteration variable", &x)
// ok to continue
}
}
if key == nil {
check.errorf(x.pos(), "cannot range over %s", &x)
// if we don't have a declaration, we can still check the loop's body
if !decl {
check.stmt(s.Body)
}
return
}
// check assignment to/declaration of iteration variables
// TODO(gri) The error messages/positions are not great here,
// they refer to the expression in the range clause.
// Should give better messages w/o too much code
// duplication (assignment checking).
if s.Key != nil {
x.typ = key
check.assign1to1(s.Key, nil, &x, decl, -1)
} else {
check.invalidAST(s.Pos(), "range clause requires index iteration variable")
// ok to continue
}
if s.Value != nil {
x.typ = val
check.assign1to1(s.Value, nil, &x, decl, -1)
}
check.stmt(s.Body)
default:
check.errorf(s.Pos(), "invalid statement")

View File

@ -40,8 +40,17 @@ type (
)
// invalid array types
type (
p1 pi /* ERROR "no field or method foo" */ .foo
iA0 [... /* ERROR "invalid use of '...'" */ ]byte
iA1 [1 /* ERROR "invalid array length" */ <<100]int
iA2 [- /* ERROR "invalid array length" */ 1]complex128
iA3 ["foo" /* ERROR "invalid array length" */ ]string
)
type (
p1 pi /* ERROR "no single field or method foo" */ .foo
p2 unsafe.Pointer
)
@ -131,7 +140,7 @@ type (
m1(I5)
}
I6 interface {
S0 /* ERROR "non-interface" */
S0 /* ERROR "not an interface" */
}
I7 interface {
I1

View File

@ -73,7 +73,7 @@ var (
// Various more complex expressions
var (
u1 = x /* ERROR "non-interface type" */ .(int)
u1 = x /* ERROR "not an interface" */ .(int)
u2 = iface.([]int)
u3 = iface.(a /* ERROR "not a type" */ )
u4, ok = iface.(int)

View File

@ -6,43 +6,43 @@
package expr3
// TODO(gri) Move the code below into function "shifts" once we check
// declarations with initilizations inside functions.
var (
i0 int
u0 uint
)
func shifts1() {
var (
i0 int
u0 uint
)
var (
v0 = 1<<0
v1 = 1<<i0 /* ERROR "must be unsigned" */
v2 = 1<<u0
v3 = 1<<"foo" /* ERROR "must be unsigned" */
v4 = 1<<- /* ERROR "stupid shift" */ 1
v5 = 1<<1025 /* ERROR "stupid shift" */
v6 = 1 /* ERROR "overflows" */ <<100
var (
v0 = 1<<0
v1 = 1<<i0 /* ERROR "must be unsigned" */
v2 = 1<<u0
v3 = 1<<"foo" /* ERROR "must be unsigned" */
v4 = 1<<- /* ERROR "stupid shift" */ 1
v5 = 1<<1025 /* ERROR "stupid shift" */
v6 = 1 /* ERROR "overflows" */ <<100
v10 uint = 1 << 0
v11 uint = 1 << u0
v12 float32 = 1 /* ERROR "must be integer" */ << u0
)
v10 uint = 1 << 0
v11 uint = 1 << u0
v12 float32 = 1 /* ERROR "must be integer" */ << u0
)
}
// TODO(gri) enable commented out tests below.
// from the spec
var (
s uint = 33
i = 1<<s // 1 has type int
j int32 = 1<<s // 1 has type int32; j == 0
k = uint64(1<<s) // 1 has type uint64; k == 1<<33
m int = 1.0<<s // 1.0 has type int
// n = 1.0<<s != 0 // 1.0 has type int; n == false if ints are 32bits in size
o = 1<<s == 2<<s // 1 and 2 have type int; o == true if ints are 32bits in size
// p = 1<<s == 1 /* ERROR "overflows" */ <<33 // illegal if ints are 32bits in size: 1 has type int, but 1<<33 overflows int
u = 1.0 /* ERROR "must be integer" */ <<s // illegal: 1.0 has type float64, cannot shift
v float32 = 1 /* ERROR "must be integer" */ <<s // illegal: 1 has type float32, cannot shift
w int64 = 1.0<<33 // 1.0<<33 is a constant shift expression
)
func shifts2() {
// TODO(gri) enable commented out tests below.
var (
s uint = 33
i = 1<<s // 1 has type int
j int32 = 1<<s // 1 has type int32; j == 0
k = uint64(1<<s) // 1 has type uint64; k == 1<<33
m int = 1.0<<s // 1.0 has type int
// n = 1.0<<s != 0 // 1.0 has type int; n == false if ints are 32bits in size
o = 1<<s == 2<<s // 1 and 2 have type int; o == true if ints are 32bits in size
// p = 1<<s == 1 /* ERROR "overflows" */ <<33 // illegal if ints are 32bits in size: 1 has type int, but 1<<33 overflows int
u = 1.0 /* ERROR "must be integer" */ <<s // illegal: 1.0 has type float64, cannot shift
v float32 = 1 /* ERROR "must be integer" */ <<s // illegal: 1 has type float32, cannot shift
w int64 = 1.0<<33 // 1.0<<33 is a constant shift expression
)
}
// TODO(gri) The error messages below depond on adjusting the spec
// to reflect what gc is doing at the moment (the spec
@ -67,11 +67,24 @@ func indexes() {
a1 = a /* ERROR "cannot assign" */ [1]
_ = a[9]
_ = a[10 /* ERROR "index .* out of bounds" */ ]
_ = a[1 /* ERROR "stupid index" */ <<100]
_ = a[10:]
_ = a[:10]
_ = a[10:10]
_ = a[11 /* ERROR "index .* out of bounds" */ :]
_ = a[: 11 /* ERROR "index .* out of bounds" */ ]
_ = a[: 1 /* ERROR "stupid index" */ <<100]
pa := &a
_ = pa[9]
_ = pa[10 /* ERROR "index .* out of bounds" */ ]
_ = pa[1 /* ERROR "stupid index" */ <<100]
_ = pa[10:]
_ = pa[:10]
_ = pa[10:10]
_ = pa[11 /* ERROR "index .* out of bounds" */ :]
_ = pa[: 11 /* ERROR "index .* out of bounds" */ ]
_ = pa[: 1 /* ERROR "stupid index" */ <<100]
var b [0]int
_ = b[0 /* ERROR "index .* out of bounds" */ ]
@ -88,11 +101,9 @@ func indexes() {
_ = s[1 : 2]
_ = s[2 /* ERROR "inverted slice range" */ : 1]
_ = s[2 :]
_ = s[: 1<<100]
_ = s[1<<100 :]
_ = s[1<<100 : 1<<100]
_ = s[1 /* ERROR "inverted slice range" */ <<100+1 : 1<<100]
_ = s[1 /* ERROR "inverted slice range" */ <<100+1 : 10]
_ = s[: 1 /* ERROR "stupid index" */ <<100]
_ = s[1 /* ERROR "stupid index" */ <<100 :]
_ = s[1 /* ERROR "stupid index" */ <<100 : 1 /* ERROR "stupid index" */ <<100]
var t string
_ = t[- /* ERROR "index .* negative" */ 1]
@ -126,9 +137,152 @@ type T struct {
func (*T) m() {}
func method_expressions() {
_ = T /* ERROR "no field or method" */ .a
_ = T /* ERROR "no single field or method" */ .a
_ = T /* ERROR "has no method" */ .x
_ = T.m
var f func(*T) = (*T).m
var g func(*T) = ( /* ERROR "cannot assign" */ T).m
}
}
func struct_literals() {
type T0 struct {
a, b, c int
}
type T1 struct {
T0
a, b int
u float64
s string
}
// keyed elements
_ = T1{}
_ = T1{a: 0, 1 /* ERROR "mixture of .* elements" */ }
_ = T1{aa /* ERROR "unknown field" */ : 0}
_ = T1{1 /* ERROR "invalid field name" */ : 0}
_ = T1{a: 0, s: "foo", u: 0, a /* ERROR "duplicate field" */: 10}
_ = T1{a: "foo" /* ERROR "cannot use" */ }
_ = T1{c /* ERROR "unknown field" */ : 0}
_ = T1{T0: { /* ERROR "missing type" */ }}
_ = T1{T0: T0{}}
_ = T1{T0 /* ERROR "invalid field name" */ .a: 0}
// unkeyed elements
_ = T0{1, 2, 3}
_ = T0{1, b /* ERROR "mixture" */ : 2, 3}
_ = T0{1, 2} /* ERROR "too few values" */
_ = T0{1, 2, 3, 4 /* ERROR "too many values" */ }
_ = T0{1, "foo" /* ERROR "cannot use" */, 3.4 /* ERROR "cannot use" */}
}
func array_literals() {
type A0 [0]int
_ = A0{}
_ = A0{0 /* ERROR "index .* out of bounds" */}
_ = A0{0 /* ERROR "index .* out of bounds" */ : 0}
type A1 [10]int
_ = A1{}
_ = A1{0, 1, 2}
_ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
_ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 /* ERROR "index .* out of bounds" */ }
_ = A1{- /* ERROR "index .* negative" */ 1: 0}
_ = A1{8: 8, 9}
_ = A1{8: 8, 9, 10 /* ERROR "index .* out of bounds" */ }
_ = A1{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
_ = A1{5: 5, 6, 7, 3: 3, 4}
_ = A1{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ }
_ = A1{10 /* ERROR "index .* out of bounds" */ : 10, 10 /* ERROR "index .* out of bounds" */ : 10}
_ = A1{5: 5, 6, 7, 3: 3, 1 /* ERROR "stupid index" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
_ = A1{5: 5, 6, 7, 4: 4, 1 /* ERROR "stupid index" */ <<100: 4}
_ = A1{2.0}
_ = A1{2.1 /* ERROR "cannot use" */ }
_ = A1{"foo" /* ERROR "cannot use" */ }
a0 := [...]int{}
assert(len(a0) == 0)
a1 := [...]int{0, 1, 2}
assert(len(a1) == 3)
var a13 [3]int
var a14 [4]int
a13 = a1
a14 = a1 /* ERROR "cannot assign" */
a2 := [...]int{- /* ERROR "index .* negative" */ 1: 0}
a3 := [...]int{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
assert(len(a3) == 5) // somewhat arbitrary
a4 := [...]complex128{0, 1, 2, 1<<10-2: -1i, 1i, 400: 10, 12, 14}
assert(len(a4) == 1024)
// from the spec
type Point struct { x, y float32 }
_ = [...]Point{Point{1.5, -3.5}, Point{0, 0}}
_ = [...]Point{{1.5, -3.5}, {0, 0}}
_ = [][]int{[]int{1, 2, 3}, []int{4, 5}}
_ = [][]int{{1, 2, 3}, {4, 5}}
_ = [...]*Point{&Point{1.5, -3.5}, &Point{0, 0}}
_ = [...]*Point{{1.5, -3.5}, {0, 0}}
}
func slice_literals() {
type S0 []int
_ = S0{}
_ = S0{0, 1, 2}
_ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
_ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
_ = S0{- /* ERROR "index .* negative" */ 1: 0}
_ = S0{8: 8, 9}
_ = S0{8: 8, 9, 10}
_ = S0{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
_ = S0{5: 5, 6, 7, 3: 3, 4}
_ = S0{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ }
_ = S0{10: 10, 10 /* ERROR "duplicate index" */ : 10}
_ = S0{5: 5, 6, 7, 3: 3, 1 /* ERROR "stupid index" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
_ = S0{5: 5, 6, 7, 4: 4, 1 /* ERROR "stupid index" */ <<100: 4}
_ = S0{2.0}
_ = S0{2.1 /* ERROR "cannot use" */ }
_ = S0{"foo" /* ERROR "cannot use" */ }
}
func map_literals() {
type M0 map[string]int
_ = M0{}
_ = M0{1 /* ERROR "missing key" */ }
_ = M0{1 /* ERROR "cannot use .* as string key" */ : 2}
_ = M0{"foo": "bar" /* ERROR "cannot use .* as int value" */ }
_ = M0{"foo": 1, "bar": 2, "foo" /* ERROR "duplicate key" */ : 3 }
}
type I interface {
m()
}
type I2 interface {
m(int)
}
type T1 struct{}
type T2 struct{}
func (T2) m(int) {}
func type_asserts() {
var x int
_ = x /* ERROR "not an interface" */ .(int)
var e interface{}
var ok bool
x, ok = e.(int)
var t I
_ = t /* ERROR "use of .* outside type switch" */ .(type)
_ = t.(T)
_ = t.(T1 /* ERROR "missing method m" */ )
_ = t.(T2 /* ERROR "wrong type for method m" */ )
_ = t.(I2 /* ERROR "wrong type for method m" */ )
}

View File

@ -71,4 +71,170 @@ func _selects() {
x = t
case <-sc /* ERROR "cannot receive from send-only channel" */ :
}
select {
default:
default /* ERROR "multiple defaults" */ :
}
}
func _gos() {
go 1 /* ERROR "expected function/method call" */
go _gos()
var c chan int
go close(c)
go len(c) // TODO(gri) this should not be legal
}
func _defers() {
defer 1 /* ERROR "expected function/method call" */
defer _defers()
var c chan int
defer close(c)
defer len(c) // TODO(gri) this should not be legal
}
func _switches() {
var x int
switch x {
default:
default /* ERROR "multiple defaults" */ :
}
// TODO(gri) more tests
}
type I interface {
m()
}
type I2 interface {
m(int)
}
type T struct{}
type T1 struct{}
type T2 struct{}
func (T) m() {}
func (T2) m(int) {}
func _typeswitches() {
var i int
var x interface{}
switch x.(type) {}
switch (x /* ERROR "outside type switch" */ .(type)) {}
switch x.(type) {
default:
default /* ERROR "multiple defaults" */ :
}
switch x := x.(type) {}
switch x := x.(type) {
case int:
var y int = x
}
switch x := i /* ERROR "not an interface" */ .(type) {}
switch t := x.(type) {
case nil:
var v bool = t /* ERROR "cannot assign" */
case int:
var v int = t
case float32, complex64:
var v float32 = t /* ERROR "cannot assign" */
default:
var v float32 = t /* ERROR "cannot assign" */
}
var t I
switch t.(type) {
case T:
case T1 /* ERROR "missing method m" */ :
case T2 /* ERROR "wrong type for method m" */ :
case I2 /* ERROR "wrong type for method m" */ :
}
}
func _rangeloops() {
var (
x int
a [10]float32
b []string
p *[10]complex128
pp **[10]complex128
s string
m map[int]bool
c chan int
sc chan<- int
rc <-chan int
)
for _ = range x /* ERROR "cannot range over" */ {}
for i := range x /* ERROR "cannot range over" */ {}
for i := range a {
var ii int
ii = i
}
for i, x := range a {
var ii int
ii = i
var xx float64
xx = x /* ERROR "cannot assign" */
}
var ii int
var xx float32
for ii, xx := range a {}
for i := range b {
var ii int
ii = i
}
for i, x := range b {
var ii int
ii = i
var xx string
xx = x
}
for i := range s {
var ii int
ii = i
}
for i, x := range s {
var ii int
ii = i
var xx rune
xx = x
}
for _, x := range p {
var xx complex128
xx = x
}
for _, x := range pp /* ERROR "cannot range over" */ {}
for k := range m {
var kk int32
kk = k /* ERROR "cannot assign" */
}
for k, v := range m {
var kk int
kk = k
if v {}
}
for _, _ /* ERROR "only one iteration variable" */ = range c {}
for e := range c {
var ee int
ee = e
}
for _ = range sc /* ERROR "cannot range over send-only channel" */ {}
for _ = range rc {}
}

View File

@ -126,6 +126,15 @@ type Struct struct {
Fields []*StructField
}
func (typ *Struct) fieldIndex(name string) int {
for i, f := range typ.Fields {
if f.Name == name {
return i
}
}
return -1
}
// A Pointer represents a pointer type *Base.
type Pointer struct {
implementsType

View File

@ -116,10 +116,12 @@ func init() {
// error type
{
res := ast.NewObj(ast.Var, "")
res.Type = Typ[String]
err := ast.NewObj(ast.Fun, "Error")
err.Type = &Signature{Results: ObjList{res}}
obj := def(ast.Typ, "error")
// TODO(gri) set up correct interface type
typ := &NamedType{Underlying: &Interface{}, Obj: obj}
obj.Type = typ
obj.Type = &NamedType{Underlying: &Interface{Methods: ObjList{err}}, Obj: obj}
}
// predeclared constants

View File

@ -9,6 +9,7 @@ package winfsnotify
import (
"io/ioutil"
"os"
"sync/atomic"
"testing"
"time"
)
@ -105,14 +106,14 @@ func TestNotifyClose(t *testing.T) {
watcher, _ := NewWatcher()
watcher.Close()
done := false
var done int32
go func() {
watcher.Close()
done = true
atomic.StoreInt32(&done, 1)
}()
time.Sleep(50 * time.Millisecond)
if !done {
if atomic.LoadInt32(&done) == 0 {
t.Fatal("double Close() test failed: second Close() call didn't return")
}

View File

@ -583,6 +583,7 @@ var mallocTest = []struct {
var _ bytes.Buffer
func TestCountMallocs(t *testing.T) {
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
for _, mt := range mallocTest {
const N = 100
memstats := new(runtime.MemStats)

View File

@ -20,7 +20,7 @@ func SortImports(fset *token.FileSet, f *File) {
break
}
if d.Lparen == token.NoPos {
if !d.Lparen.IsValid() {
// Not a block: sorted by default.
continue
}

View File

@ -0,0 +1,200 @@
// 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.
// Package format implements standard formatting of Go source.
package format
import (
"bytes"
"fmt"
"go/ast"
"go/parser"
"go/printer"
"go/token"
"io"
"strings"
)
var config = printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8}
// Node formats node in canonical gofmt style and writes the result to dst.
//
// The node type must be *ast.File, *printer.CommentedNode, []ast.Decl,
// []ast.Stmt, or assignment-compatible to ast.Expr, ast.Decl, ast.Spec,
// or ast.Stmt. Node does not modify node. Imports are not sorted for
// nodes representing partial source files (i.e., if the node is not an
// *ast.File or a *printer.CommentedNode not wrapping an *ast.File).
//
// The function may return early (before the entire result is written)
// and return a formatting error, for instance due to an incorrect AST.
//
func Node(dst io.Writer, fset *token.FileSet, node interface{}) error {
// Determine if we have a complete source file (file != nil).
var file *ast.File
var cnode *printer.CommentedNode
switch n := node.(type) {
case *ast.File:
file = n
case *printer.CommentedNode:
if f, ok := n.Node.(*ast.File); ok {
file = f
cnode = n
}
}
// Sort imports if necessary.
if file != nil && hasUnsortedImports(file) {
// Make a copy of the AST because ast.SortImports is destructive.
// TODO(gri) Do this more efficently.
var buf bytes.Buffer
err := config.Fprint(&buf, fset, file)
if err != nil {
return err
}
file, err = parser.ParseFile(fset, "", buf.Bytes(), parser.ParseComments)
if err != nil {
// We should never get here. If we do, provide good diagnostic.
return fmt.Errorf("format.Node internal error (%s)", err)
}
ast.SortImports(fset, file)
// Use new file with sorted imports.
node = file
if cnode != nil {
node = &printer.CommentedNode{Node: file, Comments: cnode.Comments}
}
}
return config.Fprint(dst, fset, node)
}
// Source formats src in canonical gofmt style and writes the result to dst
// or returns an I/O or syntax error. src is expected to be a syntactically
// correct Go source file, or a list of Go declarations or statements.
//
// If src is a partial source file, the leading and trailing space of src
// is applied to the result (such that it has the same leading and trailing
// space as src), and the formatted src is indented by the same amount as
// the first line of src containing code. Imports are not sorted for partial
// source files.
//
func Source(src []byte) ([]byte, error) {
fset := token.NewFileSet()
node, err := parse(fset, src)
if err != nil {
return nil, err
}
var buf bytes.Buffer
if file, ok := node.(*ast.File); ok {
// Complete source file.
ast.SortImports(fset, file)
err := config.Fprint(&buf, fset, file)
if err != nil {
return nil, err
}
} else {
// 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 // index of last line in leading space
}
j++
}
buf.Write(src[:i])
// Determine 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
}
// Format the source.
cfg := config
cfg.Indent = indent
err := cfg.Fprint(&buf, fset, node)
if err != nil {
return nil, err
}
// Determine and append trailing space.
i = len(src)
for i > 0 && isSpace(src[i-1]) {
i--
}
buf.Write(src[i:])
}
return buf.Bytes(), nil
}
func hasUnsortedImports(file *ast.File) bool {
for _, d := range file.Decls {
d, ok := d.(*ast.GenDecl)
if !ok || d.Tok != token.IMPORT {
// Not an import declaration, so we're done.
// Imports are always first.
return false
}
if d.Lparen.IsValid() {
// For now assume all grouped imports are unsorted.
// TODO(gri) Should check if they are sorted already.
return true
}
// Ungrouped imports are sorted by default.
}
return false
}
func isSpace(b byte) bool {
return b == ' ' || b == '\t' || b == '\n' || b == '\r'
}
func parse(fset *token.FileSet, src []byte) (interface{}, error) {
// Try as a complete source file.
file, err := parser.ParseFile(fset, "", src, parser.ParseComments)
if err == nil {
return file, nil
}
// If the source is missing a package clause, try as a source fragment; otherwise fail.
if !strings.Contains(err.Error(), "expected 'package'") {
return nil, err
}
// Try as a declaration list by prepending a package clause in front of src.
// Use ';' not '\n' to keep line numbers intact.
psrc := append([]byte("package p;"), src...)
file, err = parser.ParseFile(fset, "", psrc, parser.ParseComments)
if err == nil {
return file.Decls, nil
}
// If the source is missing a declaration, try as a statement list; otherwise fail.
if !strings.Contains(err.Error(), "expected declaration") {
return nil, err
}
// Try as statement list by wrapping a function around src.
fsrc := append(append([]byte("package p; func _() {"), src...), '}')
file, err = parser.ParseFile(fset, "", fsrc, parser.ParseComments)
if err == nil {
return file.Decls[0].(*ast.FuncDecl).Body.List, nil
}
// Failed, and out of options.
return nil, err
}

View File

@ -0,0 +1,125 @@
// 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.
package format
import (
"bytes"
"go/parser"
"go/token"
"io/ioutil"
"strings"
"testing"
)
const testfile = "format_test.go"
func diff(t *testing.T, dst, src []byte) {
line := 1
offs := 0 // line offset
for i := 0; i < len(dst) && i < len(src); i++ {
d := dst[i]
s := src[i]
if d != s {
t.Errorf("dst:%d: %s\n", line, dst[offs:i+1])
t.Errorf("src:%d: %s\n", line, src[offs:i+1])
return
}
if s == '\n' {
line++
offs = i + 1
}
}
if len(dst) != len(src) {
t.Errorf("len(dst) = %d, len(src) = %d\nsrc = %q", len(dst), len(src), src)
}
}
func TestNode(t *testing.T) {
src, err := ioutil.ReadFile(testfile)
if err != nil {
t.Fatal(err)
}
fset := token.NewFileSet()
file, err := parser.ParseFile(fset, testfile, src, parser.ParseComments)
if err != nil {
t.Fatal(err)
}
var buf bytes.Buffer
if err = Node(&buf, fset, file); err != nil {
t.Fatal("Node failed:", err)
}
diff(t, buf.Bytes(), src)
}
func TestSource(t *testing.T) {
src, err := ioutil.ReadFile(testfile)
if err != nil {
t.Fatal(err)
}
res, err := Source(src)
if err != nil {
t.Fatal("Source failed:", err)
}
diff(t, res, src)
}
// Test cases that are expected to fail are marked by the prefix "ERROR".
var tests = []string{
// declaration lists
`import "go/format"`,
"var x int",
"var x int\n\ntype T struct{}",
// statement lists
"x := 0",
"f(a, b, c)\nvar x int = f(1, 2, 3)",
// indentation, leading and trailing space
"\tx := 0\n\tgo f()",
"\tx := 0\n\tgo f()\n\n\n",
"\n\t\t\n\n\tx := 0\n\tgo f()\n\n\n",
"\n\t\t\n\n\t\t\tx := 0\n\t\t\tgo f()\n\n\n",
"\n\t\t\n\n\t\t\tx := 0\n\t\t\tconst s = `\nfoo\n`\n\n\n", // no indentation inside raw strings
// erroneous programs
"ERRORvar x",
"ERROR1 + 2 +",
"ERRORx := 0",
}
func String(s string) (string, error) {
res, err := Source([]byte(s))
if err != nil {
return "", err
}
return string(res), nil
}
func TestPartial(t *testing.T) {
for _, src := range tests {
if strings.HasPrefix(src, "ERROR") {
// test expected to fail
src = src[5:] // remove ERROR prefix
res, err := String(src)
if err == nil && res == src {
t.Errorf("formatting succeeded but was expected to fail:\n%q", src)
}
} else {
// test expected to succeed
res, err := String(src)
if err != nil {
t.Errorf("formatting failed (%s):\n%q", err, src)
} else if res != src {
t.Errorf("formatting incorrect:\nsource: %q\nresult: %q", src, res)
}
}
}
}

View File

@ -578,14 +578,15 @@ func (p *parser) parseTypeName() ast.Expr {
return ident
}
func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
func (p *parser) parseArrayType() ast.Expr {
if p.trace {
defer un(trace(p, "ArrayType"))
}
lbrack := p.expect(token.LBRACK)
var len ast.Expr
if ellipsisOk && p.tok == token.ELLIPSIS {
// always permit ellipsis for more fault-tolerant parsing
if p.tok == token.ELLIPSIS {
len = &ast.Ellipsis{Ellipsis: p.pos}
p.next()
} else if p.tok != token.RBRACK {
@ -697,7 +698,7 @@ func (p *parser) tryVarType(isParam bool) ast.Expr {
if isParam && p.tok == token.ELLIPSIS {
pos := p.pos
p.next()
typ := p.tryIdentOrType(isParam) // don't use parseType so we can provide better error message
typ := p.tryIdentOrType() // don't use parseType so we can provide better error message
if typ != nil {
p.resolve(typ)
} else {
@ -706,7 +707,7 @@ func (p *parser) tryVarType(isParam bool) ast.Expr {
}
return &ast.Ellipsis{Ellipsis: pos, Elt: typ}
}
return p.tryIdentOrType(false)
return p.tryIdentOrType()
}
// If the result is an identifier, it is not resolved.
@ -943,12 +944,12 @@ func (p *parser) parseChanType() *ast.ChanType {
}
// If the result is an identifier, it is not resolved.
func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
func (p *parser) tryIdentOrType() ast.Expr {
switch p.tok {
case token.IDENT:
return p.parseTypeName()
case token.LBRACK:
return p.parseArrayType(ellipsisOk)
return p.parseArrayType()
case token.STRUCT:
return p.parseStructType()
case token.MUL:
@ -975,7 +976,7 @@ func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
}
func (p *parser) tryType() ast.Expr {
typ := p.tryIdentOrType(false)
typ := p.tryIdentOrType()
if typ != nil {
p.resolve(typ)
}
@ -1083,7 +1084,7 @@ func (p *parser) parseOperand(lhs bool) ast.Expr {
return p.parseFuncTypeOrLit()
}
if typ := p.tryIdentOrType(true); typ != nil {
if typ := p.tryIdentOrType(); typ != nil {
// could be type for composite literal or conversion
_, isIdent := typ.(*ast.Ident)
assert(!isIdent, "type cannot be identifier")
@ -1802,7 +1803,7 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
//
// switch t := 0; t := x.(T) { ... }
//
// (this code is not valid Go because the first t will
// (this code is not valid Go because the first t
// cannot be accessed and thus is never used, the extra
// scope is needed for the correct error message).
//

View File

@ -730,7 +730,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
case *ast.FuncLit:
p.expr(x.Type)
p.funcBody(x.Body, p.distance(x.Type.Pos(), p.pos), true)
p.adjBlock(p.distanceFrom(x.Type.Pos()), blank, x.Body)
case *ast.ParenExpr:
if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
@ -900,7 +900,11 @@ func (p *printer) stmtList(list []ast.Stmt, nindent int, nextIsRBrace bool) {
if _, isEmpty := s.(*ast.EmptyStmt); !isEmpty {
// _indent == 0 only for lists of switch/select case clauses;
// in those cases each clause is a new section
p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || nindent == 0 || multiLine)
if len(p.output) > 0 {
// only print line break if we are not at the beginning of the output
// (i.e., we are not printing only a partial program)
p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || nindent == 0 || multiLine)
}
p.stmt(s, nextIsRBrace && i == len(list)-1)
multiLine = p.isMultiLine(s)
i++
@ -912,11 +916,11 @@ func (p *printer) stmtList(list []ast.Stmt, nindent int, nextIsRBrace bool) {
}
// block prints an *ast.BlockStmt; it always spans at least two lines.
func (p *printer) block(s *ast.BlockStmt, nindent int) {
p.print(s.Pos(), token.LBRACE)
p.stmtList(s.List, nindent, true)
p.linebreak(p.lineFor(s.Rbrace), 1, ignore, true)
p.print(s.Rbrace, token.RBRACE)
func (p *printer) block(b *ast.BlockStmt, nindent int) {
p.print(b.Lbrace, token.LBRACE)
p.stmtList(b.List, nindent, true)
p.linebreak(p.lineFor(b.Rbrace), 1, ignore, true)
p.print(b.Rbrace, token.RBRACE)
}
func isTypeName(x ast.Expr) bool {
@ -1421,19 +1425,19 @@ func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
return
}
func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
// bodySize is like nodeSize but it is specialized for *ast.BlockStmt's.
func (p *printer) bodySize(b *ast.BlockStmt, maxSize int) int {
pos1 := b.Pos()
pos2 := b.Rbrace
if pos1.IsValid() && pos2.IsValid() && p.lineFor(pos1) != p.lineFor(pos2) {
// opening and closing brace are on different lines - don't make it a one-liner
return false
return maxSize + 1
}
if len(b.List) > 5 || p.commentBefore(p.posFor(pos2)) {
// too many statements or there is a comment inside - don't make it a one-liner
return false
return maxSize + 1
}
// otherwise, estimate body size
const maxSize = 100
bodySize := 0
for i, s := range b.List {
if i > 0 {
@ -1441,19 +1445,23 @@ func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
}
bodySize += p.nodeSize(s, maxSize)
}
return headerSize+bodySize <= maxSize
return bodySize
}
func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool) {
// adjBlock prints an "adjacent" block (e.g., a for-loop or function body) following
// a header (e.g., a for-loop control clause or function signature) of given headerSize.
// If the header's and block's size are "small enough" and the block is "simple enough",
// the block is printed on the current line, without line breaks, spaced from the header
// by sep. Otherwise the block's opening "{" is printed on the current line, followed by
// lines for the block's statements and its closing "}".
//
func (p *printer) adjBlock(headerSize int, sep whiteSpace, b *ast.BlockStmt) {
if b == nil {
return
}
if p.isOneLineFunc(b, headerSize) {
sep := vtab
if isLit {
sep = blank
}
const maxSize = 100
if headerSize+p.bodySize(b, maxSize) <= maxSize {
p.print(sep, b.Lbrace, token.LBRACE)
if len(b.List) > 0 {
p.print(blank)
@ -1469,17 +1477,20 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool) {
return
}
p.print(blank)
if sep != ignore {
p.print(blank) // always use blank
}
p.block(b, 1)
}
// distance returns the column difference between from and to if both
// are on the same line; if they are on different lines (or unknown)
// the result is infinity.
func (p *printer) distance(from0 token.Pos, to token.Position) int {
from := p.posFor(from0)
if from.IsValid() && to.IsValid() && from.Line == to.Line {
return to.Column - from.Column
// distanceFrom returns the column difference between from and p.pos (the current
// estimated position) if both are on the same line; if they are on different lines
// (or unknown) the result is infinity.
func (p *printer) distanceFrom(from token.Pos) int {
if from.IsValid() && p.pos.IsValid() {
if f := p.posFor(from); f.Line == p.pos.Line {
return p.pos.Column - f.Column
}
}
return infinity
}
@ -1493,7 +1504,7 @@ func (p *printer) funcDecl(d *ast.FuncDecl) {
}
p.expr(d.Name)
p.signature(d.Type.Params, d.Type.Results)
p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false)
p.adjBlock(p.distanceFrom(d.Pos()), vtab, d.Body)
}
func (p *printer) decl(decl ast.Decl) {
@ -1523,31 +1534,35 @@ func declToken(decl ast.Decl) (tok token.Token) {
return
}
func (p *printer) file(src *ast.File) {
p.setComment(src.Doc)
p.print(src.Pos(), token.PACKAGE, blank)
p.expr(src.Name)
if len(src.Decls) > 0 {
tok := token.ILLEGAL
for _, d := range src.Decls {
prev := tok
tok = declToken(d)
// if the declaration token changed (e.g., from CONST to TYPE)
// or the next declaration has documentation associated with it,
// print an empty line between top-level declarations
// (because p.linebreak is called with the position of d, which
// is past any documentation, the minimum requirement is satisfied
// even w/o the extra getDoc(d) nil-check - leave it in case the
// linebreak logic improves - there's already a TODO).
func (p *printer) declList(list []ast.Decl) {
tok := token.ILLEGAL
for _, d := range list {
prev := tok
tok = declToken(d)
// If the declaration token changed (e.g., from CONST to TYPE)
// or the next declaration has documentation associated with it,
// print an empty line between top-level declarations.
// (because p.linebreak is called with the position of d, which
// is past any documentation, the minimum requirement is satisfied
// even w/o the extra getDoc(d) nil-check - leave it in case the
// linebreak logic improves - there's already a TODO).
if len(p.output) > 0 {
// only print line break if we are not at the beginning of the output
// (i.e., we are not printing only a partial program)
min := 1
if prev != tok || getDoc(d) != nil {
min = 2
}
p.linebreak(p.lineFor(d.Pos()), min, ignore, false)
p.decl(d)
}
p.decl(d)
}
}
func (p *printer) file(src *ast.File) {
p.setComment(src.Doc)
p.print(src.Pos(), token.PACKAGE, blank)
p.expr(src.Name)
p.declList(src.Decls)
p.print(newline)
}

View File

@ -20,7 +20,7 @@ import (
var testfile *ast.File
func testprint(out io.Writer, file *ast.File) {
if err := (&Config{TabIndent | UseSpaces, 8}).Fprint(out, fset, file); err != nil {
if err := (&Config{TabIndent | UseSpaces, 8, 0}).Fprint(out, fset, file); err != nil {
log.Fatalf("print error: %s", err)
}
}

View File

@ -165,15 +165,15 @@ func (p *printer) atLineBegin(pos token.Position) {
// write indentation
// use "hard" htabs - indentation columns
// must not be discarded by the tabwriter
for i := 0; i < p.indent; i++ {
n := p.Config.Indent + p.indent // include base indentation
for i := 0; i < n; i++ {
p.output = append(p.output, '\t')
}
// update positions
i := p.indent
p.pos.Offset += i
p.pos.Column += i
p.out.Column += i
p.pos.Offset += n
p.pos.Column += n
p.out.Column += n
}
// writeByte writes ch n times to p.output and updates p.pos.
@ -452,7 +452,7 @@ func trimRight(s string) string {
// stripCommonPrefix removes a common prefix from /*-style comment lines (unless no
// comment line is indented, all but the first line have some form of space prefix).
// The prefix is computed using heuristics such that is is likely that the comment
// The prefix is computed using heuristics such that is likely that the comment
// contents are nicely laid out after re-printing each line using the printer's
// current indentation.
//
@ -1032,9 +1032,9 @@ func (p *printer) printNode(node interface{}) error {
case ast.Expr:
p.expr(n)
case ast.Stmt:
// A labeled statement will un-indent to position the
// label. Set indent to 1 so we don't get indent "underflow".
if _, labeledStmt := n.(*ast.LabeledStmt); labeledStmt {
// A labeled statement will un-indent to position the label.
// Set p.indent to 1 so we don't get indent "underflow".
if _, ok := n.(*ast.LabeledStmt); ok {
p.indent = 1
}
p.stmt(n, false)
@ -1042,6 +1042,17 @@ func (p *printer) printNode(node interface{}) error {
p.decl(n)
case ast.Spec:
p.spec(n, 1, false)
case []ast.Stmt:
// A labeled statement will un-indent to position the label.
// Set p.indent to 1 so we don't get indent "underflow".
for _, s := range n {
if _, ok := s.(*ast.LabeledStmt); ok {
p.indent = 1
}
}
p.stmtList(n, 0, false)
case []ast.Decl:
p.declList(n)
case *ast.File:
p.file(n)
default:
@ -1174,6 +1185,7 @@ const (
type Config struct {
Mode Mode // default: 0
Tabwidth int // default: 8
Indent int // default: 0 (all code is indented at least by this much)
}
// fprint implements Fprint and takes a nodesSizes map for setting up the printer state.
@ -1235,8 +1247,8 @@ type CommentedNode struct {
// Fprint "pretty-prints" an AST node to output for a given configuration cfg.
// Position information is interpreted relative to the file set fset.
// The node type must be *ast.File, *CommentedNode, or assignment-compatible
// to ast.Expr, ast.Decl, ast.Spec, or ast.Stmt.
// The node type must be *ast.File, *CommentedNode, []ast.Decl, []ast.Stmt,
// or assignment-compatible to ast.Expr, ast.Decl, ast.Spec, or ast.Stmt.
//
func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{}) error {
return cfg.fprint(output, fset, node, make(map[ast.Node]int))

View File

@ -434,6 +434,98 @@ func (t *t) foo(a, b, c int) int {
}
}
var decls = []string{
`import "fmt"`,
"const pi = 3.1415\nconst e = 2.71828\n\nvar x = pi",
"func sum(x, y int) int\t{ return x + y }",
}
func TestDeclLists(t *testing.T) {
for _, src := range decls {
file, err := parser.ParseFile(fset, "", "package p;"+src, parser.ParseComments)
if err != nil {
panic(err) // error in test
}
var buf bytes.Buffer
err = Fprint(&buf, fset, file.Decls) // only print declarations
if err != nil {
panic(err) // error in test
}
out := buf.String()
if out != src {
t.Errorf("\ngot : %q\nwant: %q\n", out, src)
}
}
}
var stmts = []string{
"i := 0",
"select {}\nvar a, b = 1, 2\nreturn a + b",
"go f()\ndefer func() {}()",
}
func TestStmtLists(t *testing.T) {
for _, src := range stmts {
file, err := parser.ParseFile(fset, "", "package p; func _() {"+src+"}", parser.ParseComments)
if err != nil {
panic(err) // error in test
}
var buf bytes.Buffer
err = Fprint(&buf, fset, file.Decls[0].(*ast.FuncDecl).Body.List) // only print statements
if err != nil {
panic(err) // error in test
}
out := buf.String()
if out != src {
t.Errorf("\ngot : %q\nwant: %q\n", out, src)
}
}
}
func TestBaseIndent(t *testing.T) {
// The testfile must not contain multi-line raw strings since those
// are not indented (because their values must not change) and make
// this test fail.
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
}
var buf bytes.Buffer
for indent := 0; indent < 4; indent++ {
buf.Reset()
(&Config{Tabwidth: tabwidth, Indent: indent}).Fprint(&buf, fset, file)
// all code must be indented by at least 'indent' tabs
lines := bytes.Split(buf.Bytes(), []byte{'\n'})
for i, line := range lines {
if len(line) == 0 {
continue // empty lines don't have indentation
}
n := 0
for j, b := range line {
if b != '\t' {
// end of indentation
n = j
break
}
}
if n < indent {
t.Errorf("line %d: got only %d tabs; want at least %d: %q", i, n, indent, line)
}
}
}
}
// TestFuncType tests that an ast.FuncType with a nil Params field
// can be printed (per go/ast specification). Test case for issue 3870.
func TestFuncType(t *testing.T) {

View File

@ -241,7 +241,7 @@ func _() {
}
}
// Formatting of for-statement headers.
// Formatting of for-statement headers for single-line for-loops.
func _() {
for {
}
@ -279,6 +279,86 @@ func _() {
} // no parens printed
}
// Formatting of for-statement headers for multi-line for-loops.
func _() {
for {
}
for expr {
}
for expr {
} // no parens printed
for {
} // no semicolons printed
for x := expr; ; {
use(x)
}
for expr {
} // no semicolons printed
for expr {
} // no semicolons and parens printed
for ; ; expr = false {
}
for x := expr; expr; {
use(x)
}
for x := expr; ; expr = false {
use(x)
}
for ; expr; expr = false {
}
for x := expr; expr; expr = false {
use(x)
}
for x := range []int{} {
use(x)
}
for x := range []int{} {
use(x)
} // no parens printed
}
// Formatting of selected short single- and multi-line statements.
func _() {
if cond {
}
if cond {
} // multiple lines
if cond {
} else {
} // else clause always requires multiple lines
for {
}
for i := 0; i < len(a); 1++ {
}
for i := 0; i < len(a); 1++ {
a[i] = i
}
for i := 0; i < len(a); 1++ {
a[i] = i
} // multiple lines
for i := range a {
}
for i := range a {
a[i] = i
}
for i := range a {
a[i] = i
} // multiple lines
go func() {
for {
a <- <-b
}
}()
defer func() {
if x := recover(); x != nil {
err = fmt.Sprintf("error: %s", x.msg)
}
}()
}
// Don't remove mandatory parentheses around composite literals in control clauses.
func _() {
// strip parentheses - no composite literals or composite literals don't start with a type name

View File

@ -223,7 +223,7 @@ func _() {
}
// Formatting of for-statement headers.
// Formatting of for-statement headers for single-line for-loops.
func _() {
for{}
for expr {}
@ -235,14 +235,70 @@ func _() {
for; ; expr = false {}
for x :=expr; expr; {use(x)}
for x := expr;; expr=false {use(x)}
for;expr;expr =false {
}
for;expr;expr =false {}
for x := expr;expr;expr = false { use(x) }
for x := range []int{} { use(x) }
for x := range (([]int{})) { use(x) } // no parens printed
}
// Formatting of for-statement headers for multi-line for-loops.
func _() {
for{
}
for expr {
}
for (expr) {
} // no parens printed
for;;{
} // no semicolons printed
for x :=expr;; {use( x)
}
for; expr;{
} // no semicolons printed
for; ((expr));{
} // no semicolons and parens printed
for; ; expr = false {
}
for x :=expr; expr; {use(x)
}
for x := expr;; expr=false {use(x)
}
for;expr;expr =false {
}
for x := expr;expr;expr = false {
use(x)
}
for x := range []int{} {
use(x) }
for x := range (([]int{})) {
use(x) } // no parens printed
}
// Formatting of selected short single- and multi-line statements.
func _() {
if cond {}
if cond {
} // multiple lines
if cond {} else {} // else clause always requires multiple lines
for {}
for i := 0; i < len(a); 1++ {}
for i := 0; i < len(a); 1++ { a[i] = i }
for i := 0; i < len(a); 1++ { a[i] = i
} // multiple lines
for i := range a {}
for i := range a { a[i] = i }
for i := range a { a[i] = i
} // multiple lines
go func() { for { a <- <-b } }()
defer func() { if x := recover(); x != nil { err = fmt.Sprintf("error: %s", x.msg) } }()
}
// Don't remove mandatory parentheses around composite literals in control clauses.
func _() {
// strip parentheses - no composite literals or composite literals don't start with a type name

View File

@ -14,7 +14,7 @@ import (
)
// nextJSCtx returns the context that determines whether a slash after the
// given run of tokens tokens starts a regular expression instead of a division
// given run of tokens starts a regular expression instead of a division
// operator: / or /=.
//
// This assumes that the token run does not include any string tokens, comment

View File

@ -163,7 +163,7 @@ func (d *decoder) processDHT(n int) error {
// Returns the next Huffman-coded value from the bit stream, decoded according to h.
// TODO(nigeltao): This decoding algorithm is simple, but slow. A lookahead table, instead of always
// peeling off only 1 bit at at time, ought to be faster.
// peeling off only 1 bit at time, ought to be faster.
func (d *decoder) decodeHuffman(h *huffman) (uint8, error) {
if h.length == 0 {
return 0, FormatError("uninitialized Huffman table")

View File

@ -4,9 +4,9 @@
// +build !windows,!plan9
// Package syslog provides a simple interface to the system log service. It
// can send messages to the syslog daemon using UNIX domain sockets, UDP, or
// TCP connections.
// Package syslog provides a simple interface to the system log
// service. It can send messages to the syslog daemon using UNIX
// domain sockets, UDP, or TCP connections.
package syslog
import (
@ -15,11 +15,21 @@ import (
"log"
"net"
"os"
"time"
)
// The Priority is a combination of the syslog facility and
// severity. For example, LOG_ALERT | LOG_FTP sends an alert severity
// message from the FTP facility. The default severity is LOG_EMERG;
// the default facility is LOG_KERN.
type Priority int
const severityMask = 0x07
const facilityMask = 0xf8
const (
// Severity.
// From /usr/include/sys/syslog.h.
// These are the same on Linux, BSD, and OS X.
LOG_EMERG Priority = iota
@ -32,16 +42,47 @@ const (
LOG_DEBUG
)
const (
// Facility.
// From /usr/include/sys/syslog.h.
// These are the same up to LOG_FTP on Linux, BSD, and OS X.
LOG_KERN Priority = iota << 3
LOG_USER
LOG_MAIL
LOG_DAEMON
LOG_AUTH
LOG_SYSLOG
LOG_LPR
LOG_NEWS
LOG_UUCP
LOG_CRON
LOG_AUTHPRIV
LOG_FTP
_ // unused
_ // unused
_ // unused
_ // unused
LOG_LOCAL0
LOG_LOCAL1
LOG_LOCAL2
LOG_LOCAL3
LOG_LOCAL4
LOG_LOCAL5
LOG_LOCAL6
LOG_LOCAL7
)
// A Writer is a connection to a syslog server.
type Writer struct {
priority Priority
prefix string
tag string
hostname string
conn serverConn
}
type serverConn interface {
writeBytes(p Priority, prefix string, b []byte) (int, error)
writeString(p Priority, prefix string, s string) (int, error)
writeString(p Priority, hostname, tag, s string) (int, error)
close() error
}
@ -49,116 +90,130 @@ type netConn struct {
conn net.Conn
}
// New establishes a new connection to the system log daemon.
// Each write to the returned writer sends a log message with
// the given priority and prefix.
func New(priority Priority, prefix string) (w *Writer, err error) {
return Dial("", "", priority, prefix)
// New establishes a new connection to the system log daemon. Each
// write to the returned writer sends a log message with the given
// priority and prefix.
func New(priority Priority, tag string) (w *Writer, err error) {
return Dial("", "", priority, tag)
}
// Dial establishes a connection to a log daemon by connecting
// to address raddr on the network net.
// Each write to the returned writer sends a log message with
// the given priority and prefix.
func Dial(network, raddr string, priority Priority, prefix string) (w *Writer, err error) {
if prefix == "" {
prefix = os.Args[0]
// Dial establishes a connection to a log daemon by connecting to
// address raddr on the network net. Each write to the returned
// writer sends a log message with the given facility, severity and
// tag.
func Dial(network, raddr string, priority Priority, tag string) (w *Writer, err error) {
if priority < 0 || priority > LOG_LOCAL7|LOG_DEBUG {
return nil, errors.New("log/syslog: invalid priority")
}
if tag == "" {
tag = os.Args[0]
}
hostname, _ := os.Hostname()
var conn serverConn
if network == "" {
conn, err = unixSyslog()
if hostname == "" {
hostname = "localhost"
}
} else {
var c net.Conn
c, err = net.Dial(network, raddr)
conn = netConn{c}
if hostname == "" {
hostname = c.LocalAddr().String()
}
}
return &Writer{priority, prefix, conn}, err
if err != nil {
return nil, err
}
return &Writer{priority: priority, tag: tag, hostname: hostname, conn: conn}, nil
}
// Write sends a log message to the syslog daemon.
func (w *Writer) Write(b []byte) (int, error) {
if w.priority > LOG_DEBUG || w.priority < LOG_EMERG {
return 0, errors.New("log/syslog: invalid priority")
}
return w.conn.writeBytes(w.priority, w.prefix, b)
}
func (w *Writer) writeString(p Priority, s string) (int, error) {
return w.conn.writeString(p, w.prefix, s)
return w.writeString(w.priority, string(b))
}
func (w *Writer) Close() error { return w.conn.close() }
// Emerg logs a message using the LOG_EMERG priority.
// Emerg logs a message with severity LOG_EMERG, ignoring the severity
// passed to New.
func (w *Writer) Emerg(m string) (err error) {
_, err = w.writeString(LOG_EMERG, m)
return err
}
// Alert logs a message using the LOG_ALERT priority.
// Alert logs a message with severity LOG_ALERT, ignoring the severity
// passed to New.
func (w *Writer) Alert(m string) (err error) {
_, err = w.writeString(LOG_ALERT, m)
return err
}
// Crit logs a message using the LOG_CRIT priority.
// Crit logs a message with severity LOG_CRIT, ignoring the severity
// passed to New.
func (w *Writer) Crit(m string) (err error) {
_, err = w.writeString(LOG_CRIT, m)
return err
}
// Err logs a message using the LOG_ERR priority.
// Err logs a message with severity LOG_ERR, ignoring the severity
// passed to New.
func (w *Writer) Err(m string) (err error) {
_, err = w.writeString(LOG_ERR, m)
return err
}
// Warning logs a message using the LOG_WARNING priority.
// Wanring logs a message with severity LOG_WARNING, ignoring the
// severity passed to New.
func (w *Writer) Warning(m string) (err error) {
_, err = w.writeString(LOG_WARNING, m)
return err
}
// Notice logs a message using the LOG_NOTICE priority.
// Notice logs a message with severity LOG_NOTICE, ignoring the
// severity passed to New.
func (w *Writer) Notice(m string) (err error) {
_, err = w.writeString(LOG_NOTICE, m)
return err
}
// Info logs a message using the LOG_INFO priority.
// Info logs a message with severity LOG_INFO, ignoring the severity
// passed to New.
func (w *Writer) Info(m string) (err error) {
_, err = w.writeString(LOG_INFO, m)
return err
}
// Debug logs a message using the LOG_DEBUG priority.
// Debug logs a message with severity LOG_DEBUG, ignoring the severity
// passed to New.
func (w *Writer) Debug(m string) (err error) {
_, err = w.writeString(LOG_DEBUG, m)
return err
}
func (n netConn) writeBytes(p Priority, prefix string, b []byte) (int, error) {
nl := ""
if len(b) == 0 || b[len(b)-1] != '\n' {
nl = "\n"
}
_, err := fmt.Fprintf(n.conn, "<%d>%s: %s%s", p, prefix, b, nl)
if err != nil {
return 0, err
}
return len(b), nil
func (w *Writer) writeString(p Priority, s string) (int, error) {
return w.conn.writeString((w.priority&facilityMask)|(p&severityMask),
w.hostname, w.tag, s)
}
func (n netConn) writeString(p Priority, prefix string, s string) (int, error) {
// writeString: generates and writes a syslog formatted string. The
// format is as follows: <PRI>1 TIMESTAMP HOSTNAME TAG[PID]: MSG
func (n netConn) writeString(p Priority, hostname, tag, msg string) (int, error) {
nl := ""
if len(s) == 0 || s[len(s)-1] != '\n' {
if len(msg) == 0 || msg[len(msg)-1] != '\n' {
nl = "\n"
}
_, err := fmt.Fprintf(n.conn, "<%d>%s: %s%s", p, prefix, s, nl)
if err != nil {
timestamp := time.Now().Format(time.RFC3339)
if _, err := fmt.Fprintf(n.conn, "<%d>1 %s %s %s[%d]: %s%s", p, timestamp, hostname,
tag, os.Getpid(), msg, nl); err != nil {
return 0, err
}
return len(s), nil
return len(msg), nil
}
func (n netConn) close() error {

View File

@ -7,9 +7,11 @@
package syslog
import (
"fmt"
"io"
"log"
"net"
"os"
"testing"
"time"
)
@ -49,10 +51,14 @@ func skipNetTest(t *testing.T) bool {
}
func TestNew(t *testing.T) {
if LOG_LOCAL7 != 23<<3 {
t.Fatalf("LOG_LOCAL7 has wrong value")
}
if skipNetTest(t) {
return
}
s, err := New(LOG_INFO, "")
s, err := New(LOG_INFO|LOG_USER, "")
if err != nil {
t.Fatalf("New() failed: %s", err)
}
@ -64,7 +70,7 @@ func TestNewLogger(t *testing.T) {
if skipNetTest(t) {
return
}
f, err := NewLogger(LOG_INFO, 0)
f, err := NewLogger(LOG_USER|LOG_INFO, 0)
if f == nil {
t.Error(err)
}
@ -74,7 +80,15 @@ func TestDial(t *testing.T) {
if skipNetTest(t) {
return
}
l, err := Dial("", "", LOG_ERR, "syslog_test")
f, err := Dial("", "", (LOG_LOCAL7|LOG_DEBUG)+1, "syslog_test")
if f != nil {
t.Fatalf("Should have trapped bad priority")
}
f, err = Dial("", "", -1, "syslog_test")
if f != nil {
t.Fatalf("Should have trapped bad priority")
}
l, err := Dial("", "", LOG_USER|LOG_ERR, "syslog_test")
if err != nil {
t.Fatalf("Dial() failed: %s", err)
}
@ -84,16 +98,23 @@ func TestDial(t *testing.T) {
func TestUDPDial(t *testing.T) {
done := make(chan string)
startServer(done)
l, err := Dial("udp", serverAddr, LOG_INFO, "syslog_test")
l, err := Dial("udp", serverAddr, LOG_USER|LOG_INFO, "syslog_test")
if err != nil {
t.Fatalf("syslog.Dial() failed: %s", err)
}
msg := "udp test"
l.Info(msg)
expected := "<6>syslog_test: udp test\n"
expected := fmt.Sprintf("<%d>1 ", LOG_USER+LOG_INFO) + "%s %s syslog_test[%d]: udp test\n"
rcvd := <-done
if rcvd != expected {
t.Fatalf("s.Info() = '%q', but wanted '%q'", rcvd, expected)
var parsedHostname, timestamp string
var pid int
if hostname, err := os.Hostname(); err != nil {
t.Fatalf("Error retrieving hostname")
} else {
if n, err := fmt.Sscanf(rcvd, expected, &timestamp, &parsedHostname, &pid); n != 3 ||
err != nil || hostname != parsedHostname {
t.Fatalf("s.Info() = '%q', didn't match '%q'", rcvd, expected)
}
}
}
@ -104,26 +125,34 @@ func TestWrite(t *testing.T) {
msg string
exp string
}{
{LOG_ERR, "syslog_test", "", "<3>syslog_test: \n"},
{LOG_ERR, "syslog_test", "write test", "<3>syslog_test: write test\n"},
{LOG_USER | LOG_ERR, "syslog_test", "", "%s %s syslog_test[%d]: \n"},
{LOG_USER | LOG_ERR, "syslog_test", "write test", "%s %s syslog_test[%d]: write test\n"},
// Write should not add \n if there already is one
{LOG_ERR, "syslog_test", "write test 2\n", "<3>syslog_test: write test 2\n"},
{LOG_USER | LOG_ERR, "syslog_test", "write test 2\n", "%s %s syslog_test[%d]: write test 2\n"},
}
for _, test := range tests {
done := make(chan string)
startServer(done)
l, err := Dial("udp", serverAddr, test.pri, test.pre)
if err != nil {
t.Fatalf("syslog.Dial() failed: %s", err)
}
_, err = io.WriteString(l, test.msg)
if err != nil {
t.Fatalf("WriteString() failed: %s", err)
}
rcvd := <-done
if rcvd != test.exp {
t.Fatalf("s.Info() = '%q', but wanted '%q'", rcvd, test.exp)
if hostname, err := os.Hostname(); err != nil {
t.Fatalf("Error retrieving hostname")
} else {
for _, test := range tests {
done := make(chan string)
startServer(done)
l, err := Dial("udp", serverAddr, test.pri, test.pre)
if err != nil {
t.Fatalf("syslog.Dial() failed: %s", err)
}
_, err = io.WriteString(l, test.msg)
if err != nil {
t.Fatalf("WriteString() failed: %s", err)
}
rcvd := <-done
test.exp = fmt.Sprintf("<%d>1 ", test.pri) + test.exp
var parsedHostname, timestamp string
var pid int
if n, err := fmt.Sscanf(rcvd, test.exp, &timestamp, &parsedHostname, &pid); n != 3 ||
err != nil || hostname != parsedHostname {
t.Fatalf("s.Info() = '%q', didn't match '%q'", rcvd, test.exp)
}
}
}
}

View File

@ -180,6 +180,7 @@ func allocBytes(f func()) uint64 {
// does not cause deep recursion and in turn allocate too much memory.
// Test case for issue 3807.
func TestMulUnbalanced(t *testing.T) {
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
x := rndNat(50000)
y := rndNat(40)
allocSize := allocBytes(func() {

View File

@ -37,6 +37,11 @@ type Part struct {
disposition string
dispositionParams map[string]string
// r is either a reader directly reading from mr, or it's a
// wrapper around such a reader, decoding the
// Content-Transfer-Encoding
r io.Reader
}
// FormName returns the name parameter if p has a Content-Disposition
@ -94,6 +99,12 @@ func newPart(mr *Reader) (*Part, error) {
if err := bp.populateHeaders(); err != nil {
return nil, err
}
bp.r = partReader{bp}
const cte = "Content-Transfer-Encoding"
if bp.Header.Get(cte) == "quoted-printable" {
bp.Header.Del(cte)
bp.r = newQuotedPrintableReader(bp.r)
}
return bp, nil
}
@ -109,6 +120,17 @@ func (bp *Part) populateHeaders() error {
// Read reads the body of a part, after its headers and before the
// next part (if any) begins.
func (p *Part) Read(d []byte) (n int, err error) {
return p.r.Read(d)
}
// partReader implements io.Reader by reading raw bytes directly from the
// wrapped *Part, without doing any Transfer-Encoding decoding.
type partReader struct {
p *Part
}
func (pr partReader) Read(d []byte) (n int, err error) {
p := pr.p
defer func() {
p.bytesRead += n
}()

View File

@ -339,9 +339,10 @@ func TestLineContinuation(t *testing.T) {
if err != nil {
t.Fatalf("didn't get a part")
}
n, err := io.Copy(ioutil.Discard, part)
var buf bytes.Buffer
n, err := io.Copy(&buf, part)
if err != nil {
t.Errorf("error reading part: %v", err)
t.Errorf("error reading part: %v\nread so far: %q", err, buf.String())
}
if n <= 0 {
t.Errorf("read %d bytes; expected >0", n)
@ -349,6 +350,29 @@ func TestLineContinuation(t *testing.T) {
}
}
func TestQuotedPrintableEncoding(t *testing.T) {
// From http://golang.org/issue/4411
body := "--0016e68ee29c5d515f04cedf6733\r\nContent-Type: text/plain; charset=ISO-8859-1\r\nContent-Disposition: form-data; name=text\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nwords words words words words words words words words words words words wor=\r\nds words words words words words words words words words words words words =\r\nwords words words words words words words words words words words words wor=\r\nds words words words words words words words words words words words words =\r\nwords words words words words words words words words\r\n--0016e68ee29c5d515f04cedf6733\r\nContent-Type: text/plain; charset=ISO-8859-1\r\nContent-Disposition: form-data; name=submit\r\n\r\nSubmit\r\n--0016e68ee29c5d515f04cedf6733--"
r := NewReader(strings.NewReader(body), "0016e68ee29c5d515f04cedf6733")
part, err := r.NextPart()
if err != nil {
t.Fatal(err)
}
if te, ok := part.Header["Content-Transfer-Encoding"]; ok {
t.Errorf("unexpected Content-Transfer-Encoding of %q", te)
}
var buf bytes.Buffer
_, err = io.Copy(&buf, part)
if err != nil {
t.Error(err)
}
got := buf.String()
want := "words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words"
if got != want {
t.Errorf("wrong part value:\n got: %q\nwant: %q", got, want)
}
}
// Test parsing an image attachment from gmail, which previously failed.
func TestNested(t *testing.T) {
// nested-mime is the body part of a multipart/mixed email

View File

@ -0,0 +1,92 @@
// 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.
// The file define a quoted-printable decoder, as specified in RFC 2045.
package multipart
import (
"bufio"
"bytes"
"fmt"
"io"
)
type qpReader struct {
br *bufio.Reader
rerr error // last read error
line []byte // to be consumed before more of br
}
func newQuotedPrintableReader(r io.Reader) io.Reader {
return &qpReader{
br: bufio.NewReader(r),
}
}
func fromHex(b byte) (byte, error) {
switch {
case b >= '0' && b <= '9':
return b - '0', nil
case b >= 'A' && b <= 'F':
return b - 'A' + 10, nil
}
return 0, fmt.Errorf("multipart: invalid quoted-printable hex byte 0x%02x", b)
}
func (q *qpReader) readHexByte(v []byte) (b byte, err error) {
if len(v) < 2 {
return 0, io.ErrUnexpectedEOF
}
var hb, lb byte
if hb, err = fromHex(v[0]); err != nil {
return 0, err
}
if lb, err = fromHex(v[1]); err != nil {
return 0, err
}
return hb<<4 | lb, nil
}
func isQPDiscardWhitespace(r rune) bool {
switch r {
case '\n', '\r', ' ', '\t':
return true
}
return false
}
func (q *qpReader) Read(p []byte) (n int, err error) {
for len(p) > 0 {
if len(q.line) == 0 {
if q.rerr != nil {
return n, q.rerr
}
q.line, q.rerr = q.br.ReadSlice('\n')
q.line = bytes.TrimRightFunc(q.line, isQPDiscardWhitespace)
continue
}
if len(q.line) == 1 && q.line[0] == '=' {
// Soft newline; skipped.
q.line = nil
continue
}
b := q.line[0]
switch {
case b == '=':
b, err = q.readHexByte(q.line[1:])
if err != nil {
return n, err
}
q.line = q.line[2:] // 2 of the 3; other 1 is done below
case b != '\t' && (b < ' ' || b > '~'):
return n, fmt.Errorf("multipart: invalid unescaped byte 0x%02x in quoted-printable body", b)
}
p[0] = b
p = p[1:]
q.line = q.line[1:]
n++
}
return n, nil
}

View File

@ -0,0 +1,52 @@
// 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.
package multipart
import (
"bytes"
"fmt"
"io"
"strings"
"testing"
)
func TestQuotedPrintable(t *testing.T) {
tests := []struct {
in, want string
err interface{}
}{
{in: "foo bar", want: "foo bar"},
{in: "foo bar=3D", want: "foo bar="},
{in: "foo bar=0", want: "foo bar", err: io.ErrUnexpectedEOF},
{in: "foo bar=ab", want: "foo bar", err: "multipart: invalid quoted-printable hex byte 0x61"},
{in: "foo bar=0D=0A", want: "foo bar\r\n"},
{in: "foo bar=\r\n baz", want: "foo bar baz"},
{in: "foo=\nbar", want: "foobar"},
{in: "foo\x00bar", want: "foo", err: "multipart: invalid unescaped byte 0x00 in quoted-printable body"},
{in: "foo bar\xff", want: "foo bar", err: "multipart: invalid unescaped byte 0xff in quoted-printable body"},
}
for _, tt := range tests {
var buf bytes.Buffer
_, err := io.Copy(&buf, newQuotedPrintableReader(strings.NewReader(tt.in)))
if got := buf.String(); got != tt.want {
t.Errorf("for %q, got %q; want %q", tt.in, got, tt.want)
}
switch verr := tt.err.(type) {
case nil:
if err != nil {
t.Errorf("for %q, got unexpected error: %v", tt.in, err)
}
case string:
if got := fmt.Sprint(err); got != verr {
t.Errorf("for %q, got error %q; want %q", tt.in, got, verr)
}
case error:
if err != verr {
t.Errorf("for %q, got error %q; want %q", tt.in, err, verr)
}
}
}
}

View File

@ -30,11 +30,38 @@ func NewWriter(w io.Writer) *Writer {
}
}
// Boundary returns the Writer's randomly selected boundary string.
// Boundary returns the Writer's boundary.
func (w *Writer) Boundary() string {
return w.boundary
}
// SetBoundary overrides the Writer's default randomly-generated
// boundary separator with an explicit value.
//
// SetBoundary must be called before any parts are created, may only
// contain certain ASCII characters, and must be 1-69 bytes long.
func (w *Writer) SetBoundary(boundary string) error {
if w.lastpart != nil {
return errors.New("mime: SetBoundary called after write")
}
// rfc2046#section-5.1.1
if len(boundary) < 1 || len(boundary) > 69 {
return errors.New("mime: invalid boundary length")
}
for _, b := range boundary {
if 'A' <= b && b <= 'Z' || 'a' <= b && b <= 'z' || '0' <= b && b <= '9' {
continue
}
switch b {
case '\'', '(', ')', '+', '_', ',', '-', '.', '/', ':', '=', '?':
continue
}
return errors.New("mime: invalid boundary character")
}
w.boundary = boundary
return nil
}
// FormDataContentType returns the Content-Type for an HTTP
// multipart/form-data with this Writer's Boundary.
func (w *Writer) FormDataContentType() string {

View File

@ -7,6 +7,7 @@ package multipart
import (
"bytes"
"io/ioutil"
"strings"
"testing"
)
@ -76,3 +77,37 @@ func TestWriter(t *testing.T) {
t.Fatalf("expected end of parts; got %v, %v", part, err)
}
}
func TestWriterSetBoundary(t *testing.T) {
var b bytes.Buffer
w := NewWriter(&b)
tests := []struct {
b string
ok bool
}{
{"abc", true},
{"", false},
{"ungültig", false},
{"!", false},
{strings.Repeat("x", 69), true},
{strings.Repeat("x", 70), false},
{"bad!ascii!", false},
{"my-separator", true},
}
for i, tt := range tests {
err := w.SetBoundary(tt.b)
got := err == nil
if got != tt.ok {
t.Errorf("%d. boundary %q = %v (%v); want %v", i, tt.b, got, err, tt.ok)
} else if tt.ok {
got := w.Boundary()
if got != tt.b {
t.Errorf("boundary = %q; want %q", got, tt.b)
}
}
}
w.Close()
if got := b.String(); !strings.Contains(got, "\r\n--my-separator--\r\n") {
t.Errorf("expected my-separator in output. got: %q", got)
}
}

View File

@ -15,6 +15,7 @@ func parseDialNetwork(net string) (afnet string, proto int, err error) {
switch net {
case "tcp", "tcp4", "tcp6":
case "udp", "udp4", "udp6":
case "ip", "ip4", "ip6":
case "unix", "unixgram", "unixpacket":
default:
return "", 0, UnknownNetworkError(net)
@ -54,12 +55,8 @@ func resolveAfnetAddr(afnet, addr string, deadline time.Time) (Addr, error) {
return nil, nil
}
switch afnet {
case "tcp", "tcp4", "tcp6":
return resolveTCPAddr(afnet, addr, deadline)
case "udp", "udp4", "udp6":
return resolveUDPAddr(afnet, addr, deadline)
case "ip", "ip4", "ip6":
return resolveIPAddr(afnet, addr, deadline)
case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "ip", "ip4", "ip6":
return resolveInternetAddr(afnet, addr, deadline)
case "unix", "unixgram", "unixpacket":
return ResolveUnixAddr(afnet, addr)
}
@ -218,8 +215,8 @@ func Listen(net, laddr string) (Listener, error) {
// ListenPacket announces on the local network address laddr.
// The network string net must be a packet-oriented network:
// "udp", "udp4", "udp6", "ip", "ip4", "ip6" or "unixgram".
func ListenPacket(net, addr string) (PacketConn, error) {
afnet, a, err := resolveNetAddr("listen", net, addr, noDeadline)
func ListenPacket(net, laddr string) (PacketConn, error) {
afnet, a, err := resolveNetAddr("listen", net, laddr, noDeadline)
if err != nil {
return nil, err
}

View File

@ -0,0 +1,57 @@
// 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 freebsd linux netbsd openbsd windows
package net
import (
"testing"
"time"
)
var deadlineSetTimeTests = []struct {
input time.Time
expected int64
}{
{time.Time{}, 0},
{time.Date(2009, 11, 10, 23, 00, 00, 00, time.UTC), 1257894000000000000}, // 2009-11-10 23:00:00 +0000 UTC
}
func TestDeadlineSetTime(t *testing.T) {
for _, tt := range deadlineSetTimeTests {
var d deadline
d.setTime(tt.input)
actual := d.value()
expected := int64(0)
if !tt.input.IsZero() {
expected = tt.input.UnixNano()
}
if actual != expected {
t.Errorf("set/value failed: expected %v, actual %v", expected, actual)
}
}
}
var deadlineExpiredTests = []struct {
deadline time.Time
expired bool
}{
// note, times are relative to the start of the test run, not
// the start of TestDeadlineExpired
{time.Now().Add(5 * time.Minute), false},
{time.Now().Add(-5 * time.Minute), true},
{time.Time{}, false}, // no deadline set
}
func TestDeadlineExpired(t *testing.T) {
for _, tt := range deadlineExpiredTests {
var d deadline
d.set(tt.deadline.UnixNano())
expired := d.expired()
if expired != tt.expired {
t.Errorf("expire failed: expected %v, actual %v", tt.expired, expired)
}
}
}

View File

@ -37,11 +37,11 @@ type netFD struct {
laddr Addr
raddr Addr
// owned by client
rdeadline int64
rio sync.Mutex
wdeadline int64
wio sync.Mutex
// serialize access to Read and Write methods
rio, wio sync.Mutex
// read and write deadlines
rdeadline, wdeadline deadline
// owned by fd wait server
ncr, ncw int
@ -82,11 +82,11 @@ func (s *pollServer) AddFD(fd *netFD, mode int) error {
key := intfd << 1
if mode == 'r' {
fd.ncr++
t = fd.rdeadline
t = fd.rdeadline.value()
} else {
fd.ncw++
key++
t = fd.wdeadline
t = fd.wdeadline.value()
}
s.pending[key] = fd
doWakeup := false
@ -153,12 +153,8 @@ func (s *pollServer) WakeFD(fd *netFD, mode int, err error) {
}
}
func (s *pollServer) Now() int64 {
return time.Now().UnixNano()
}
func (s *pollServer) CheckDeadlines() {
now := s.Now()
now := time.Now().UnixNano()
// TODO(rsc): This will need to be handled more efficiently,
// probably with a heap indexed by wakeup time.
@ -172,21 +168,19 @@ func (s *pollServer) CheckDeadlines() {
mode = 'w'
}
if mode == 'r' {
t = fd.rdeadline
t = fd.rdeadline.value()
} else {
t = fd.wdeadline
t = fd.wdeadline.value()
}
if t > 0 {
if t <= now {
delete(s.pending, key)
if mode == 'r' {
s.poll.DelFD(fd.sysfd, mode)
fd.rdeadline = -1
} else {
s.poll.DelFD(fd.sysfd, mode)
fd.wdeadline = -1
}
s.WakeFD(fd, mode, nil)
s.WakeFD(fd, mode, errTimeout)
} else if nextDeadline == 0 || t < nextDeadline {
nextDeadline = t
}
@ -200,15 +194,15 @@ func (s *pollServer) Run() {
s.Lock()
defer s.Unlock()
for {
var t = s.deadline
if t > 0 {
t = t - s.Now()
if t <= 0 {
var timeout int64 // nsec to wait for or 0 for none
if s.deadline > 0 {
timeout = s.deadline - time.Now().UnixNano()
if timeout <= 0 {
s.CheckDeadlines()
continue
}
}
fd, mode, err := s.poll.WaitFD(s, t)
fd, mode, err := s.poll.WaitFD(s, timeout)
if err != nil {
print("pollServer WaitFD: ", err.Error(), "\n")
return
@ -329,14 +323,10 @@ func (fd *netFD) name() string {
func (fd *netFD) connect(ra syscall.Sockaddr) error {
err := syscall.Connect(fd.sysfd, ra)
hadTimeout := fd.wdeadline > 0
if err == syscall.EINPROGRESS {
if err = fd.pollServer.WaitWrite(fd); err != nil {
return err
}
if hadTimeout && fd.wdeadline < 0 {
return errTimeout
}
var e int
e, err = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
if err != nil {
@ -381,8 +371,8 @@ func (fd *netFD) decref() {
func (fd *netFD) Close() error {
fd.pollServer.Lock() // needed for both fd.incref(true) and pollserver.Evict
defer fd.pollServer.Unlock()
if err := fd.incref(true); err != nil {
fd.pollServer.Unlock()
return err
}
// Unblock any I/O. Once it all unblocks and returns,
@ -391,6 +381,7 @@ func (fd *netFD) Close() error {
// fairly quickly, since all the I/O is non-blocking, and any
// attempts to block in the pollserver will return errClosing.
fd.pollServer.Evict(fd)
fd.pollServer.Unlock()
fd.decref()
return nil
}
@ -423,20 +414,20 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
}
defer fd.decref()
for {
n, err = syscall.Read(int(fd.sysfd), p)
if err == syscall.EAGAIN {
if fd.rdeadline.expired() {
err = errTimeout
if fd.rdeadline >= 0 {
break
}
n, err = syscall.Read(int(fd.sysfd), p)
if err != nil {
n = 0
if err == syscall.EAGAIN {
if err = fd.pollServer.WaitRead(fd); err == nil {
continue
}
}
}
if err != nil {
n = 0
} else if n == 0 && err == nil && fd.sotype != syscall.SOCK_DGRAM {
err = io.EOF
}
err = chkReadErr(n, err, fd)
break
}
if err != nil && err != io.EOF {
@ -453,18 +444,20 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
}
defer fd.decref()
for {
n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0)
if err == syscall.EAGAIN {
if fd.rdeadline.expired() {
err = errTimeout
if fd.rdeadline >= 0 {
break
}
n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0)
if err != nil {
n = 0
if err == syscall.EAGAIN {
if err = fd.pollServer.WaitRead(fd); err == nil {
continue
}
}
}
if err != nil {
n = 0
}
err = chkReadErr(n, err, fd)
break
}
if err != nil && err != io.EOF {
@ -481,41 +474,47 @@ func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S
}
defer fd.decref()
for {
n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0)
if err == syscall.EAGAIN {
if fd.rdeadline.expired() {
err = errTimeout
if fd.rdeadline >= 0 {
break
}
n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0)
if err != nil {
// TODO(dfc) should n and oobn be set to 0
if err == syscall.EAGAIN {
if err = fd.pollServer.WaitRead(fd); err == nil {
continue
}
}
}
if err == nil && n == 0 {
err = io.EOF
}
err = chkReadErr(n, err, fd)
break
}
if err != nil && err != io.EOF {
err = &OpError{"read", fd.net, fd.laddr, err}
return
}
return
}
func (fd *netFD) Write(p []byte) (int, error) {
func chkReadErr(n int, err error, fd *netFD) error {
if n == 0 && err == nil && fd.sotype != syscall.SOCK_DGRAM && fd.sotype != syscall.SOCK_RAW {
return io.EOF
}
return err
}
func (fd *netFD) Write(p []byte) (nn int, err error) {
fd.wio.Lock()
defer fd.wio.Unlock()
if err := fd.incref(false); err != nil {
return 0, err
}
defer fd.decref()
if fd.sysfile == nil {
return 0, syscall.EINVAL
}
var err error
nn := 0
for {
if fd.wdeadline.expired() {
err = errTimeout
break
}
var n int
n, err = syscall.Write(int(fd.sysfd), p[nn:])
if n > 0 {
@ -525,11 +524,8 @@ func (fd *netFD) Write(p []byte) (int, error) {
break
}
if err == syscall.EAGAIN {
err = errTimeout
if fd.wdeadline >= 0 {
if err = fd.pollServer.WaitWrite(fd); err == nil {
continue
}
if err = fd.pollServer.WaitWrite(fd); err == nil {
continue
}
}
if err != nil {
@ -555,13 +551,14 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
}
defer fd.decref()
for {
if fd.wdeadline.expired() {
err = errTimeout
break
}
err = syscall.Sendto(fd.sysfd, p, 0, sa)
if err == syscall.EAGAIN {
err = errTimeout
if fd.wdeadline >= 0 {
if err = fd.pollServer.WaitWrite(fd); err == nil {
continue
}
if err = fd.pollServer.WaitWrite(fd); err == nil {
continue
}
}
break
@ -582,13 +579,14 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
}
defer fd.decref()
for {
if fd.wdeadline.expired() {
err = errTimeout
break
}
err = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
if err == syscall.EAGAIN {
err = errTimeout
if fd.wdeadline >= 0 {
if err = fd.pollServer.WaitWrite(fd); err == nil {
continue
}
if err = fd.pollServer.WaitWrite(fd); err == nil {
continue
}
}
break
@ -619,11 +617,8 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (netfd *netFD, err e
if err != nil {
syscall.ForkLock.RUnlock()
if err == syscall.EAGAIN {
err = errTimeout
if fd.rdeadline >= 0 {
if err = fd.pollServer.WaitRead(fd); err == nil {
continue
}
if err = fd.pollServer.WaitRead(fd); err == nil {
continue
}
} else if err == syscall.ECONNABORTED {
// This means that a socket on the listen queue was closed

View File

@ -7,33 +7,34 @@
package net
import (
"io"
"syscall"
"testing"
)
// Issue 3590. netFd.AddFD should return an error
// from the underlying pollster rather than panicing.
func TestAddFDReturnsError(t *testing.T) {
l, err := Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
defer l.Close()
ln := newLocalListener(t).(*TCPListener)
defer ln.Close()
connected := make(chan bool)
go func() {
for {
c, err := l.Accept()
c, err := ln.Accept()
if err != nil {
return
}
connected <- true
defer c.Close()
}
}()
c, err := Dial("tcp", l.Addr().String())
c, err := DialTCP("tcp", nil, ln.Addr().(*TCPAddr))
if err != nil {
t.Fatal(err)
}
defer c.Close()
<-connected
// replace c's pollServer with a closed version.
ps, err := newPollServer()
@ -41,7 +42,7 @@ func TestAddFDReturnsError(t *testing.T) {
t.Fatal(err)
}
ps.poll.Close()
c.(*TCPConn).conn.fd.pollServer = ps
c.conn.fd.pollServer = ps
var b [1]byte
_, err = c.Read(b[:])
@ -56,5 +57,50 @@ func TestAddFDReturnsError(t *testing.T) {
}
}
}
t.Error(err)
t.Error("unexpected error:", err)
}
var chkReadErrTests = []struct {
n int
err error
fd *netFD
expected error
}{
{100, nil, &netFD{sotype: syscall.SOCK_STREAM}, nil},
{100, io.EOF, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF},
{100, errClosing, &netFD{sotype: syscall.SOCK_STREAM}, errClosing},
{0, nil, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF},
{0, io.EOF, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF},
{0, errClosing, &netFD{sotype: syscall.SOCK_STREAM}, errClosing},
{100, nil, &netFD{sotype: syscall.SOCK_DGRAM}, nil},
{100, io.EOF, &netFD{sotype: syscall.SOCK_DGRAM}, io.EOF},
{100, errClosing, &netFD{sotype: syscall.SOCK_DGRAM}, errClosing},
{0, nil, &netFD{sotype: syscall.SOCK_DGRAM}, nil},
{0, io.EOF, &netFD{sotype: syscall.SOCK_DGRAM}, io.EOF},
{0, errClosing, &netFD{sotype: syscall.SOCK_DGRAM}, errClosing},
{100, nil, &netFD{sotype: syscall.SOCK_SEQPACKET}, nil},
{100, io.EOF, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF},
{100, errClosing, &netFD{sotype: syscall.SOCK_SEQPACKET}, errClosing},
{0, nil, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF},
{0, io.EOF, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF},
{0, errClosing, &netFD{sotype: syscall.SOCK_SEQPACKET}, errClosing},
{100, nil, &netFD{sotype: syscall.SOCK_RAW}, nil},
{100, io.EOF, &netFD{sotype: syscall.SOCK_RAW}, io.EOF},
{100, errClosing, &netFD{sotype: syscall.SOCK_RAW}, errClosing},
{0, nil, &netFD{sotype: syscall.SOCK_RAW}, nil},
{0, io.EOF, &netFD{sotype: syscall.SOCK_RAW}, io.EOF},
{0, errClosing, &netFD{sotype: syscall.SOCK_RAW}, errClosing},
}
func TestChkReadErr(t *testing.T) {
for _, tt := range chkReadErrTests {
actual := chkReadErr(tt.n, tt.err, tt.fd)
if actual != tt.expected {
t.Errorf("chkReadError(%v, %v, %v): expected %v, actual %v", tt.n, tt.err, tt.fd.sotype, tt.expected, actual)
}
}
}

View File

@ -169,6 +169,15 @@ func (s *ioSrv) ProcessRemoteIO() {
func (s *ioSrv) ExecIO(oi anOpIface, deadline int64) (int, error) {
var err error
o := oi.Op()
// Calculate timeout delta.
var delta int64
if deadline != 0 {
delta = deadline - time.Now().UnixNano()
if delta <= 0 {
return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, errTimeout}
}
}
// Start IO.
if canCancelIO {
err = oi.Submit()
} else {
@ -188,12 +197,8 @@ func (s *ioSrv) ExecIO(oi anOpIface, deadline int64) (int, error) {
}
// Setup timer, if deadline is given.
var timer <-chan time.Time
if deadline != 0 {
dt := deadline - time.Now().UnixNano()
if dt < 1 {
dt = 1
}
t := time.NewTimer(time.Duration(dt) * time.Nanosecond)
if delta > 0 {
t := time.NewTimer(time.Duration(delta) * time.Nanosecond)
defer t.Stop()
timer = t.C
}
@ -280,11 +285,11 @@ type netFD struct {
errnoc [2]chan error // read/write submit or cancel operation errors
closec chan bool // used by Close to cancel pending IO
// owned by client
rdeadline int64
rio sync.Mutex
wdeadline int64
wio sync.Mutex
// serialize access to Read and Write methods
rio, wio sync.Mutex
// read and write deadlines
rdeadline, wdeadline deadline
}
func allocFD(fd syscall.Handle, family, sotype int, net string) *netFD {
@ -295,7 +300,6 @@ func allocFD(fd syscall.Handle, family, sotype int, net string) *netFD {
net: net,
closec: make(chan bool),
}
runtime.SetFinalizer(netfd, (*netFD).Close)
return netfd
}
@ -314,6 +318,7 @@ func newFD(fd syscall.Handle, family, proto int, net string) (*netFD, error) {
func (fd *netFD) setAddr(laddr, raddr Addr) {
fd.laddr = laddr
fd.raddr = raddr
runtime.SetFinalizer(fd, (*netFD).closesocket)
}
func (fd *netFD) connect(ra syscall.Sockaddr) error {
@ -393,6 +398,10 @@ func (fd *netFD) CloseWrite() error {
return fd.shutdown(syscall.SHUT_WR)
}
func (fd *netFD) closesocket() error {
return closesocket(fd.sysfd)
}
// Read from network.
type readOp struct {
@ -417,7 +426,7 @@ func (fd *netFD) Read(buf []byte) (int, error) {
defer fd.rio.Unlock()
var o readOp
o.Init(fd, buf, 'r')
n, err := iosrv.ExecIO(&o, fd.rdeadline)
n, err := iosrv.ExecIO(&o, fd.rdeadline.value())
if err == nil && n == 0 {
err = io.EOF
}
@ -454,7 +463,7 @@ func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
var o readFromOp
o.Init(fd, buf, 'r')
o.rsan = int32(unsafe.Sizeof(o.rsa))
n, err = iosrv.ExecIO(&o, fd.rdeadline)
n, err = iosrv.ExecIO(&o, fd.rdeadline.value())
if err != nil {
return 0, nil, err
}
@ -486,7 +495,7 @@ func (fd *netFD) Write(buf []byte) (int, error) {
defer fd.wio.Unlock()
var o writeOp
o.Init(fd, buf, 'w')
return iosrv.ExecIO(&o, fd.wdeadline)
return iosrv.ExecIO(&o, fd.wdeadline.value())
}
// WriteTo to network.
@ -518,7 +527,7 @@ func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
var o writeToOp
o.Init(fd, buf, 'w')
o.sa = sa
return iosrv.ExecIO(&o, fd.wdeadline)
return iosrv.ExecIO(&o, fd.wdeadline.value())
}
// Accept new network connections.
@ -552,7 +561,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
s, err := syscall.Socket(fd.family, fd.sotype, 0)
if err != nil {
syscall.ForkLock.RUnlock()
return nil, err
return nil, &OpError{"socket", fd.net, fd.laddr, err}
}
syscall.CloseOnExec(s)
syscall.ForkLock.RUnlock()
@ -560,6 +569,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
// Associate our new socket with IOCP.
onceStartServer.Do(startServer)
if _, err := syscall.CreateIoCompletionPort(s, resultsrv.iocp, 0, 0); err != nil {
closesocket(s)
return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, err}
}
@ -567,7 +577,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
var o acceptOp
o.Init(fd, 'r')
o.newsock = s
_, err = iosrv.ExecIO(&o, fd.rdeadline)
_, err = iosrv.ExecIO(&o, fd.rdeadline.value())
if err != nil {
closesocket(s)
return nil, err
@ -577,7 +587,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
if err != nil {
closesocket(s)
return nil, err
return nil, &OpError{"Setsockopt", fd.net, fd.laddr, err}
}
// Get local and peer addr out of AcceptEx buffer.

View File

@ -19,8 +19,8 @@ func FileConn(f *os.File) (c Conn, err error) {
// FileListener returns a copy of the network listener corresponding
// to the open file f. It is the caller's responsibility to close l
// when finished. Closing c does not affect l, and closing l does not
// affect c.
// when finished. Closing l does not affect f, and closing f does not
// affect l.
func FileListener(f *os.File) (l Listener, err error) {
return nil, syscall.EPLAN9
}

View File

@ -405,7 +405,8 @@ func TestDirUnix(t *testing.T) {
}
func TestDirWindows(t *testing.T) {
if skipTest(t) || runtime.GOOS != "windows" {
if runtime.GOOS != "windows" {
t.Logf("Skipping windows specific test.")
return
}
@ -415,6 +416,7 @@ func TestDirWindows(t *testing.T) {
var err error
perl, err = exec.LookPath("perl")
if err != nil {
t.Logf("Skipping test: perl not found.")
return
}
perl, _ = filepath.Abs(perl)
@ -457,6 +459,7 @@ func TestEnvOverride(t *testing.T) {
var err error
perl, err = exec.LookPath("perl")
if err != nil {
t.Logf("Skipping test: perl not found.")
return
}
perl, _ = filepath.Abs(perl)

View File

@ -10,23 +10,6 @@ use Cwd;
binmode STDOUT;
sub on_windows {
return $^O eq 'MSWin32' || $^O eq 'msys';
}
# normalize_windows_path normalizes the various Windows Perl path
# formats into Go's format.
sub normalize_windows_path {
my $dir = shift;
return $dir unless on_windows();
$dir =~ s!^[a-z]:!uc($&)!e;
if ($dir =~ s!^/([a-zA-Z])/!!) {
$dir = uc($1) . ":\\$dir";
}
$dir =~ s!/!\\!g;
return $dir;
}
my $q = MiniCGI->new;
my $params = $q->Vars;
@ -35,40 +18,43 @@ if ($params->{"loc"}) {
exit(0);
}
my $NL = "\r\n";
$NL = "\n" if $params->{mode} eq "NL";
my $p = sub {
print "$_[0]$NL";
};
# With carriage returns
$p->("Content-Type: text/html");
$p->("X-CGI-Pid: $$");
$p->("X-Test-Header: X-Test-Value");
$p->("");
print "Content-Type: text/html\r\n";
print "X-CGI-Pid: $$\r\n";
print "X-Test-Header: X-Test-Value\r\n";
print "\r\n";
if ($params->{"bigresponse"}) {
for (1..1024) {
print "A" x 1024, "\n";
print "A" x 1024, "\r\n";
}
exit 0;
}
print "test=Hello CGI\n";
print "test=Hello CGI\r\n";
foreach my $k (sort keys %$params) {
print "param-$k=$params->{$k}\n";
print "param-$k=$params->{$k}\r\n";
}
foreach my $k (sort keys %ENV) {
my $clean_env = $ENV{$k};
$clean_env =~ s/[\n\r]//g;
print "env-$k=$clean_env\n";
print "env-$k=$clean_env\r\n";
}
my $dir = normalize_windows_path(getcwd());
print "cwd=$dir\n";
# NOTE: msys perl returns /c/go/src/... not C:\go\....
my $dir = getcwd();
if ($^O eq 'MSWin32' || $^O eq 'msys') {
if ($dir =~ /^.:/) {
$dir =~ s!/!\\!g;
} else {
my $cmd = $ENV{'COMSPEC'} || 'c:\\windows\\system32\\cmd.exe';
$cmd =~ s!\\!/!g;
$dir = `$cmd /c cd`;
chomp $dir;
}
}
print "cwd=$dir\r\n";
# A minimal version of CGI.pm, for people without the perl-modules
# package installed. (CGI.pm used to be part of the Perl core, but
@ -102,24 +88,3 @@ sub _urldecode {
$v =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
return $v;
}
package Tests;
sub test_normalize_windows_paths {
my @tests = (
{in => "C:\\foo\\bar", want => "C:\\foo\\bar"},
{in => "C:/foo/bar", want => "C:\\foo\\bar"},
{in => "c:/foo/bar", want => "C:\\foo\\bar"},
{in => "/c/foo/bar", want => "C:\\foo\\bar"},
);
foreach my $tt (@tests) {
my $got = ::normalize_windows_path($tt->{in});
unless ($got eq $tt->{want}) {
die "For path $tt->{in}, normalize = $got; want $tt->{want}\n";
}
}
}
BEGIN {
test_normalize_windows_paths() if ::on_windows();
}

View File

@ -11,11 +11,9 @@ package http
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"strconv"
)
const maxLineLength = 4096 // assumed <= bufio.defaultBufSize
@ -45,12 +43,12 @@ type chunkedReader struct {
func (cr *chunkedReader) beginChunk() {
// chunk-size CRLF
var line string
var line []byte
line, cr.err = readLine(cr.r)
if cr.err != nil {
return
}
cr.n, cr.err = strconv.ParseUint(line, 16, 64)
cr.n, cr.err = parseHexUint(line)
if cr.err != nil {
return
}
@ -89,7 +87,7 @@ func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
// 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 readLineBytes(b *bufio.Reader) (p []byte, err error) {
func readLine(b *bufio.Reader) (p []byte, err error) {
if p, err = b.ReadSlice('\n'); err != nil {
// We always know when EOF is coming.
// If the caller asked for a line, there should be a line.
@ -103,20 +101,18 @@ func readLineBytes(b *bufio.Reader) (p []byte, err error) {
if len(p) >= maxLineLength {
return nil, ErrLineTooLong
}
// Chop off trailing white space.
p = bytes.TrimRight(p, " \r\t\n")
return p, nil
return trimTrailingWhitespace(p), nil
}
// readLineBytes, but convert the bytes into a string.
func readLine(b *bufio.Reader) (s string, err error) {
p, e := readLineBytes(b)
if e != nil {
return "", e
func trimTrailingWhitespace(b []byte) []byte {
for len(b) > 0 && isASCIISpace(b[len(b)-1]) {
b = b[:len(b)-1]
}
return string(p), nil
return b
}
func isASCIISpace(b byte) bool {
return b == ' ' || b == '\t' || b == '\n' || b == '\r'
}
// newChunkedWriter returns a new chunkedWriter that translates writes into HTTP
@ -167,3 +163,21 @@ func (cw *chunkedWriter) Close() error {
_, err := io.WriteString(cw.Wire, "0\r\n")
return err
}
func parseHexUint(v []byte) (n uint64, err error) {
for _, b := range v {
n <<= 4
switch {
case '0' <= b && b <= '9':
b = b - '0'
case 'a' <= b && b <= 'f':
b = b - 'a' + 10
case 'A' <= b && b <= 'F':
b = b - 'A' + 10
default:
return 0, errors.New("invalid byte in chunk length")
}
n |= uint64(b)
}
return
}

View File

@ -9,7 +9,10 @@ package http
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"runtime"
"testing"
)
@ -37,3 +40,54 @@ func TestChunk(t *testing.T) {
t.Errorf("chunk reader read %q; want %q", g, e)
}
}
func TestChunkReaderAllocs(t *testing.T) {
// temporarily set GOMAXPROCS to 1 as we are testing memory allocations
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
var buf bytes.Buffer
w := newChunkedWriter(&buf)
a, b, c := []byte("aaaaaa"), []byte("bbbbbbbbbbbb"), []byte("cccccccccccccccccccccccc")
w.Write(a)
w.Write(b)
w.Write(c)
w.Close()
r := newChunkedReader(&buf)
readBuf := make([]byte, len(a)+len(b)+len(c)+1)
var ms runtime.MemStats
runtime.ReadMemStats(&ms)
m0 := ms.Mallocs
n, err := io.ReadFull(r, readBuf)
runtime.ReadMemStats(&ms)
mallocs := ms.Mallocs - m0
if mallocs > 1 {
t.Errorf("%d mallocs; want <= 1", mallocs)
}
if n != len(readBuf)-1 {
t.Errorf("read %d bytes; want %d", n, len(readBuf)-1)
}
if err != io.ErrUnexpectedEOF {
t.Errorf("read error = %v; want ErrUnexpectedEOF", err)
}
}
func TestParseHexUint(t *testing.T) {
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)
}
}
_, err := parseHexUint([]byte("bogus"))
if err == nil {
t.Error("expected error on bogus input")
}
}

View File

@ -527,3 +527,38 @@ func TestClientWithIncorrectTLSServerName(t *testing.T) {
t.Errorf("wanted error mentioning 127.0.0.1 and badserver; got error: %v", err)
}
}
// Verify Response.ContentLength is populated. http://golang.org/issue/4126
func TestClientHeadContentLength(t *testing.T) {
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if v := r.FormValue("cl"); v != "" {
w.Header().Set("Content-Length", v)
}
}))
defer ts.Close()
tests := []struct {
suffix string
want int64
}{
{"/?cl=1234", 1234},
{"/?cl=0", 0},
{"", -1},
}
for _, tt := range tests {
req, _ := NewRequest("HEAD", ts.URL+tt.suffix, nil)
res, err := DefaultClient.Do(req)
if err != nil {
t.Fatal(err)
}
if res.ContentLength != tt.want {
t.Errorf("Content-Length = %d; want %d", res.ContentLength, tt.want)
}
bs, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Fatal(err)
}
if len(bs) != 0 {
t.Errorf("Unexpected content: %q", bs)
}
}
}

View File

@ -7,7 +7,14 @@
package http
import "time"
import (
"net"
"time"
)
func NewLoggingConn(baseName string, c net.Conn) net.Conn {
return newLoggingConn(baseName, c)
}
func (t *Transport) IdleConnKeysForTesting() (keys []string) {
keys = make([]string, 0)

View File

@ -188,6 +188,7 @@ type errorfer interface {
}
func doHeaderWriteSubset(n int, t errorfer) {
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
h := Header(map[string][]string{
"Content-Length": {"123"},
"Content-Type": {"text/plain"},
@ -204,7 +205,7 @@ func doHeaderWriteSubset(n int, t errorfer) {
var m1 runtime.MemStats
runtime.ReadMemStats(&m1)
if mallocs := m1.Mallocs - m0.Mallocs; n >= 100 && mallocs >= uint64(n) {
// TODO(bradfitz,rsc): once we can sort with allocating,
// TODO(bradfitz,rsc): once we can sort without allocating,
// make this an error. See http://golang.org/issue/3761
// t.Errorf("did %d mallocs (>= %d iterations); should have avoided mallocs", mallocs, n)
}

View File

@ -21,7 +21,7 @@ import (
type Server struct {
URL string // base URL of form http://ipaddr:port with no trailing slash
Listener net.Listener
TLS *tls.Config // nil if not using using TLS
TLS *tls.Config // nil if not using TLS
// Config may be changed after calling NewUnstartedServer and
// before Start or StartTLS.
@ -36,13 +36,16 @@ type Server struct {
// accepted.
type historyListener struct {
net.Listener
history []net.Conn
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
}
@ -96,7 +99,7 @@ func (s *Server) Start() {
if s.URL != "" {
panic("Server already started")
}
s.Listener = &historyListener{s.Listener, make([]net.Conn, 0)}
s.Listener = &historyListener{Listener: s.Listener}
s.URL = "http://" + s.Listener.Addr().String()
s.wrapHandler()
go s.Config.Serve(s.Listener)
@ -122,7 +125,7 @@ func (s *Server) StartTLS() {
}
tlsListener := tls.NewListener(s.Listener, s.TLS)
s.Listener = &historyListener{tlsListener, make([]net.Conn, 0)}
s.Listener = &historyListener{Listener: tlsListener}
s.URL = "https://" + s.Listener.Addr().String()
s.wrapHandler()
go s.Config.Serve(s.Listener)
@ -152,6 +155,10 @@ func NewTLSServer(handler http.Handler) *Server {
func (s *Server) Close() {
s.Listener.Close()
s.wg.Wait()
s.CloseClientConnections()
if t, ok := http.DefaultTransport.(*http.Transport); ok {
t.CloseIdleConnections()
}
}
// CloseClientConnections closes any currently open HTTP connections
@ -161,9 +168,11 @@ func (s *Server) CloseClientConnections() {
if !ok {
return
}
hl.Lock()
for _, conn := range hl.history {
conn.Close()
}
hl.Unlock()
}
// waitGroupHandler wraps a handler, incrementing and decrementing a

View File

@ -13,11 +13,9 @@ package httputil
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"strconv"
)
const maxLineLength = 4096 // assumed <= bufio.defaultBufSize
@ -47,12 +45,12 @@ type chunkedReader struct {
func (cr *chunkedReader) beginChunk() {
// chunk-size CRLF
var line string
var line []byte
line, cr.err = readLine(cr.r)
if cr.err != nil {
return
}
cr.n, cr.err = strconv.ParseUint(line, 16, 64)
cr.n, cr.err = parseHexUint(line)
if cr.err != nil {
return
}
@ -91,7 +89,7 @@ func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
// 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 readLineBytes(b *bufio.Reader) (p []byte, err error) {
func readLine(b *bufio.Reader) (p []byte, err error) {
if p, err = b.ReadSlice('\n'); err != nil {
// We always know when EOF is coming.
// If the caller asked for a line, there should be a line.
@ -105,20 +103,18 @@ func readLineBytes(b *bufio.Reader) (p []byte, err error) {
if len(p) >= maxLineLength {
return nil, ErrLineTooLong
}
// Chop off trailing white space.
p = bytes.TrimRight(p, " \r\t\n")
return p, nil
return trimTrailingWhitespace(p), nil
}
// readLineBytes, but convert the bytes into a string.
func readLine(b *bufio.Reader) (s string, err error) {
p, e := readLineBytes(b)
if e != nil {
return "", e
func trimTrailingWhitespace(b []byte) []byte {
for len(b) > 0 && isASCIISpace(b[len(b)-1]) {
b = b[:len(b)-1]
}
return string(p), nil
return b
}
func isASCIISpace(b byte) bool {
return b == ' ' || b == '\t' || b == '\n' || b == '\r'
}
// NewChunkedWriter returns a new chunkedWriter that translates writes into HTTP
@ -169,3 +165,21 @@ func (cw *chunkedWriter) Close() error {
_, err := io.WriteString(cw.Wire, "0\r\n")
return err
}
func parseHexUint(v []byte) (n uint64, err error) {
for _, b := range v {
n <<= 4
switch {
case '0' <= b && b <= '9':
b = b - '0'
case 'a' <= b && b <= 'f':
b = b - 'a' + 10
case 'A' <= b && b <= 'F':
b = b - 'A' + 10
default:
return 0, errors.New("invalid byte in chunk length")
}
n |= uint64(b)
}
return
}

View File

@ -11,7 +11,10 @@ package httputil
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"runtime"
"testing"
)
@ -39,3 +42,54 @@ func TestChunk(t *testing.T) {
t.Errorf("chunk reader read %q; want %q", g, e)
}
}
func TestChunkReaderAllocs(t *testing.T) {
// temporarily set GOMAXPROCS to 1 as we are testing memory allocations
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
var buf bytes.Buffer
w := NewChunkedWriter(&buf)
a, b, c := []byte("aaaaaa"), []byte("bbbbbbbbbbbb"), []byte("cccccccccccccccccccccccc")
w.Write(a)
w.Write(b)
w.Write(c)
w.Close()
r := NewChunkedReader(&buf)
readBuf := make([]byte, len(a)+len(b)+len(c)+1)
var ms runtime.MemStats
runtime.ReadMemStats(&ms)
m0 := ms.Mallocs
n, err := io.ReadFull(r, readBuf)
runtime.ReadMemStats(&ms)
mallocs := ms.Mallocs - m0
if mallocs > 1 {
t.Errorf("%d mallocs; want <= 1", mallocs)
}
if n != len(readBuf)-1 {
t.Errorf("read %d bytes; want %d", n, len(readBuf)-1)
}
if err != io.ErrUnexpectedEOF {
t.Errorf("read error = %v; want ErrUnexpectedEOF", err)
}
}
func TestParseHexUint(t *testing.T) {
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)
}
}
_, err := parseHexUint([]byte("bogus"))
if err == nil {
t.Error("expected error on bogus input")
}
}

View File

@ -124,6 +124,7 @@ type Request struct {
// The host on which the URL is sought.
// Per RFC 2616, this is either the value of the Host: header
// or the host name given in the URL itself.
// It may be of the form "host:port".
Host string
// Form contains the parsed form data, including both the URL
@ -643,16 +644,20 @@ func parsePostForm(r *Request) (vs url.Values, err error) {
return
}
// ParseForm parses the raw query from the URL.
// ParseForm parses the raw query from the URL and updates r.Form.
//
// For POST or PUT requests, it also parses the request body as a form and
// put the results into both r.PostForm and r.Form.
// POST and PUT body parameters take precedence over URL query string values
// in r.Form.
//
// For POST or PUT requests, it also parses the request body as a form.
// POST and PUT body parameters take precedence over URL query string values.
// If the request Body's size has not already been limited by MaxBytesReader,
// the size is capped at 10MB.
//
// ParseMultipartForm calls ParseForm automatically.
// It is idempotent.
func (r *Request) ParseForm() (err error) {
func (r *Request) ParseForm() error {
var err error
if r.PostForm == nil {
if r.Method == "POST" || r.Method == "PUT" {
r.PostForm, err = parsePostForm(r)
@ -728,6 +733,7 @@ func (r *Request) ParseMultipartForm(maxMemory int64) error {
// FormValue returns the first value for the named component of the query.
// POST and PUT body parameters take precedence over URL query string values.
// FormValue calls ParseMultipartForm and ParseForm if necessary.
// To access multiple values of the same key use ParseForm.
func (r *Request) FormValue(key string) string {
if r.Form == nil {
r.ParseMultipartForm(defaultMaxMemory)

View File

@ -228,6 +228,16 @@ func TestReadRequestErrors(t *testing.T) {
}
}
func TestNewRequestHost(t *testing.T) {
req, err := NewRequest("GET", "http://localhost:1234/", nil)
if err != nil {
t.Fatal(err)
}
if req.Host != "localhost:1234" {
t.Errorf("Host = %q; want localhost:1234", req.Host)
}
}
func testMissingFile(t *testing.T, req *Request) {
f, fh, err := req.FormFile("missing")
if f != nil {

View File

@ -49,7 +49,7 @@ type Response struct {
Body io.ReadCloser
// ContentLength records the length of the associated content. The
// value -1 indicates that the length is unknown. Unless RequestMethod
// value -1 indicates that the length is unknown. Unless Request.Method
// is "HEAD", values >= 0 indicate that the given number of bytes may
// be read from Body.
ContentLength int64
@ -178,7 +178,7 @@ func (r *Response) ProtoAtLeast(major, minor int) bool {
// StatusCode
// ProtoMajor
// ProtoMinor
// RequestMethod
// Request.Method
// TransferEncoding
// Trailer
// Body

View File

@ -193,7 +193,7 @@ var respTests = []respTest{
Request: dummyReq("HEAD"),
Header: Header{},
Close: true,
ContentLength: 0,
ContentLength: -1,
},
"",

View File

@ -1252,6 +1252,42 @@ func TestContentLengthZero(t *testing.T) {
}
}
func TestCloseNotifier(t *testing.T) {
gotReq := make(chan bool, 1)
sawClose := make(chan bool, 1)
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)
go func() {
_, err = fmt.Fprintf(conn, "GET / HTTP/1.1\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n")
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):
t.Fatal("timeout")
}
}
ts.Close()
}
// goTimeout runs f, failing t if f takes more than ns to complete.
func goTimeout(t *testing.T, d time.Duration, f func()) {
ch := make(chan bool, 2)

View File

@ -11,7 +11,6 @@ package http
import (
"bufio"
"bytes"
"crypto/tls"
"errors"
"fmt"
@ -21,7 +20,7 @@ import (
"net"
"net/url"
"path"
"runtime/debug"
"runtime"
"strconv"
"strings"
"sync"
@ -94,16 +93,104 @@ type Hijacker interface {
Hijack() (net.Conn, *bufio.ReadWriter, error)
}
// The CloseNotifier interface is implemented by ResponseWriters which
// allow detecting when the underlying connection has gone away.
//
// 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() <-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
lr *io.LimitedReader // io.LimitReader(rwc)
buf *bufio.ReadWriter // buffered(lr,rwc), reading from bufio->limitReader->rwc
hijacked bool // connection has been hijacked by handler
sr switchReader // 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
body []byte
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
}
func (c *conn) hijacked() bool {
c.mu.Lock()
defer c.mu.Unlock()
return c.hijackedv
}
func (c *conn) hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
c.mu.Lock()
defer c.mu.Unlock()
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
return
}
func (c *conn) closeNotify() <-chan bool {
c.mu.Lock()
defer c.mu.Unlock()
if c.closeNotifyc == nil {
c.closeNotifyc = make(chan bool)
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
}
type switchReader struct {
sync.Mutex
r io.Reader
}
func (sr *switchReader) Read(p []byte) (n int, err error) {
sr.Lock()
r := sr.r
sr.Unlock()
return r.Read(p)
}
// A response represents the server side of an HTTP response.
@ -127,7 +214,7 @@ type response struct {
// requestBodyLimitHit is set by requestTooLarge when
// maxBytesReader hits its max size. It is checked in
// WriteHeader, to make sure we don't consume the the
// WriteHeader, to make sure we don't consume the
// remaining request body to try to advance to the next HTTP
// request. Instead, when this is set, we stop reading
// subsequent requests on this connection and stop reading
@ -171,16 +258,24 @@ func (w *response) ReadFrom(src io.Reader) (n int64, err error) {
// 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
if debugServerConnections {
c.rwc = newLoggingConn("server", c.rwc)
}
c.sr = switchReader{r: c.rwc}
c.body = make([]byte, sniffLen)
c.lr = io.LimitReader(rwc, noLimit).(*io.LimitedReader)
c.lr = io.LimitReader(&c.sr, noLimit).(*io.LimitedReader)
br := bufio.NewReader(c.lr)
bw := bufio.NewWriter(rwc)
bw := bufio.NewWriter(c.rwc)
c.buf = bufio.NewReadWriter(br, bw)
return c, nil
}
@ -207,9 +302,9 @@ type expectContinueReader struct {
func (ecr *expectContinueReader) Read(p []byte) (n int, err error) {
if ecr.closed {
return 0, errors.New("http: Read after Close on request Body")
return 0, ErrBodyReadAfterClose
}
if !ecr.resp.wroteContinue && !ecr.resp.conn.hijacked {
if !ecr.resp.wroteContinue && !ecr.resp.conn.hijacked() {
ecr.resp.wroteContinue = true
io.WriteString(ecr.resp.conn.buf, "HTTP/1.1 100 Continue\r\n\r\n")
ecr.resp.conn.buf.Flush()
@ -232,7 +327,7 @@ var errTooLarge = errors.New("http: request too large")
// Read next request from connection.
func (c *conn) readRequest() (w *response, err error) {
if c.hijacked {
if c.hijacked() {
return nil, ErrHijacked
}
c.lr.N = int64(c.server.maxHeaderBytes()) + 4096 /* bufio slop */
@ -273,7 +368,7 @@ func (w *response) Header() Header {
const maxPostHandlerReadBytes = 256 << 10
func (w *response) WriteHeader(code int) {
if w.conn.hijacked {
if w.conn.hijacked() {
log.Print("http: response.WriteHeader on hijacked connection")
return
}
@ -363,6 +458,8 @@ func (w *response) WriteHeader(code int) {
if w.req.Method == "HEAD" || code == StatusNotModified {
// do nothing
} else if code == StatusNoContent {
w.header.Del("Transfer-Encoding")
} else if hasCL {
w.contentLength = contentLength
w.header.Del("Transfer-Encoding")
@ -447,7 +544,7 @@ func (w *response) bodyAllowed() bool {
}
func (w *response) Write(data []byte) (n int, err error) {
if w.conn.hijacked {
if w.conn.hijacked() {
log.Print("http: response.Write on hijacked connection")
return 0, ErrHijacked
}
@ -496,7 +593,7 @@ func (w *response) Write(data []byte) (n int, err error) {
// then there would be fewer chunk headers.
// On the other hand, it would make hijacking more difficult.
if w.chunking {
fmt.Fprintf(w.conn.buf, "%x\r\n", len(data)) // TODO(rsc): use strconv not fmt
fmt.Fprintf(w.conn.buf, "%x\r\n", len(data))
}
n, err = w.conn.buf.Write(data)
if err == nil && w.chunking {
@ -517,7 +614,7 @@ func (w *response) finishRequest() {
// HTTP/1.0 clients keep their "keep-alive" connections alive, and for
// HTTP/1.1 clients is just as good as the alternative: sending a
// chunked response and immediately sending the zero-length EOF chunk.
if w.written == 0 && w.header.get("Content-Length") == "" {
if w.written == 0 && w.header.get("Content-Length") == "" && w.req.Method != "HEAD" {
w.header.Set("Content-Length", "0")
}
// If this was an HTTP/1.0 request with keep-alive and we sent a
@ -610,10 +707,10 @@ func (c *conn) serve() {
return
}
var buf bytes.Buffer
fmt.Fprintf(&buf, "http: panic serving %v: %v\n", c.remoteAddr, err)
buf.Write(debug.Stack())
log.Print(buf.String())
const size = 4096
buf := make([]byte, size)
buf = buf[:runtime.Stack(buf, false)]
log.Printf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf)
if c.rwc != nil { // may be nil if connection hijacked
c.rwc.Close()
@ -665,21 +762,7 @@ func (c *conn) serve() {
}
req.Header.Del("Expect")
} else if req.Header.get("Expect") != "" {
// TODO(bradfitz): let ServeHTTP handlers handle
// requests with non-standard expectation[s]? Seems
// theoretical at best, and doesn't fit into the
// current ServeHTTP model anyway. We'd need to
// make the ResponseWriter an optional
// "ExpectReplier" interface or something.
//
// For now we'll just obey RFC 2616 14.20 which says
// "If a server receives a request containing an
// Expect field that includes an expectation-
// extension that it does not support, it MUST
// respond with a 417 (Expectation Failed) status."
w.Header().Set("Connection", "close")
w.WriteHeader(StatusExpectationFailed)
w.finishRequest()
w.sendExpectationFailed()
break
}
@ -694,7 +777,7 @@ func (c *conn) serve() {
// [*] Not strictly true: HTTP pipelining. We could let them all process
// in parallel even if their responses need to be serialized.
handler.ServeHTTP(w, w.req)
if c.hijacked {
if c.hijacked() {
return
}
w.finishRequest()
@ -708,18 +791,32 @@ func (c *conn) serve() {
c.close()
}
func (w *response) sendExpectationFailed() {
// TODO(bradfitz): let ServeHTTP handlers handle
// requests with non-standard expectation[s]? Seems
// theoretical at best, and doesn't fit into the
// current ServeHTTP model anyway. We'd need to
// make the ResponseWriter an optional
// "ExpectReplier" interface or something.
//
// For now we'll just obey RFC 2616 14.20 which says
// "If a server receives a request containing an
// Expect field that includes an expectation-
// extension that it does not support, it MUST
// respond with a 417 (Expectation Failed) status."
w.Header().Set("Connection", "close")
w.WriteHeader(StatusExpectationFailed)
w.finishRequest()
}
// 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.conn.hijacked {
return nil, nil, ErrHijacked
}
w.conn.hijacked = true
rwc = w.conn.rwc
buf = w.conn.buf
w.conn.rwc = nil
w.conn.buf = nil
return
return w.conn.hijack()
}
func (w *response) CloseNotify() <-chan bool {
return w.conn.closeNotify()
}
// The HandlerFunc type is an adapter to allow the use of
@ -1310,3 +1407,45 @@ func (tw *timeoutWriter) WriteHeader(code int) {
tw.mu.Unlock()
tw.w.WriteHeader(code)
}
// loggingConn is used for debugging.
type loggingConn struct {
name string
net.Conn
}
var (
uniqNameMu sync.Mutex
uniqNameNext = make(map[string]int)
)
func newLoggingConn(baseName string, c net.Conn) net.Conn {
uniqNameMu.Lock()
defer uniqNameMu.Unlock()
uniqNameNext[baseName]++
return &loggingConn{
name: fmt.Sprintf("%s-%d", baseName, uniqNameNext[baseName]),
Conn: c,
}
}
func (c *loggingConn) Write(p []byte) (n int, err error) {
log.Printf("%s.Write(%d) = ....", c.name, len(p))
n, err = c.Conn.Write(p)
log.Printf("%s.Write(%d) = %d, %v", c.name, len(p), n, err)
return
}
func (c *loggingConn) Read(p []byte) (n int, err error) {
log.Printf("%s.Read(%d) = ....", c.name, len(p))
n, err = c.Conn.Read(p)
log.Printf("%s.Read(%d) = %d, %v", c.name, len(p), n, err)
return
}
func (c *loggingConn) Close() (err error) {
log.Printf("%s.Close() = ...", c.name)
err = c.Conn.Close()
log.Printf("%s.Close() = %v", c.name, err)
return
}

View File

@ -294,10 +294,19 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
return err
}
t.ContentLength, err = fixLength(isResponse, t.StatusCode, t.RequestMethod, t.Header, t.TransferEncoding)
realLength, err := fixLength(isResponse, t.StatusCode, t.RequestMethod, t.Header, t.TransferEncoding)
if err != nil {
return err
}
if isResponse && t.RequestMethod == "HEAD" {
if n, err := parseContentLength(t.Header.get("Content-Length")); err != nil {
return err
} else {
t.ContentLength = n
}
} else {
t.ContentLength = realLength
}
// Trailer
t.Trailer, err = fixTrailer(t.Header, t.TransferEncoding)
@ -310,7 +319,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
// See RFC2616, section 4.4.
switch msg.(type) {
case *Response:
if t.ContentLength == -1 &&
if realLength == -1 &&
!chunked(t.TransferEncoding) &&
bodyAllowedForStatus(t.StatusCode) {
// Unbounded body.
@ -323,11 +332,11 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
switch {
case chunked(t.TransferEncoding):
t.Body = &body{Reader: newChunkedReader(r), hdr: msg, r: r, closing: t.Close}
case t.ContentLength >= 0:
case realLength >= 0:
// TODO: limit the Content-Length. This is an easy DoS vector.
t.Body = &body{Reader: io.LimitReader(r, t.ContentLength), closing: t.Close}
t.Body = &body{Reader: io.LimitReader(r, realLength), closing: t.Close}
default:
// t.ContentLength < 0, i.e. "Content-Length" not mentioned in header
// realLength < 0, i.e. "Content-Length" not mentioned in header
if t.Close {
// Close semantics (i.e. HTTP/1.0)
t.Body = &body{Reader: r, closing: t.Close}
@ -434,9 +443,9 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,
// Logic based on Content-Length
cl := strings.TrimSpace(header.get("Content-Length"))
if cl != "" {
n, err := strconv.ParseInt(cl, 10, 64)
if err != nil || n < 0 {
return -1, &badStringError{"bad Content-Length", cl}
n, err := parseContentLength(cl)
if err != nil {
return -1, err
}
return n, nil
} else {
@ -525,11 +534,11 @@ type body struct {
res *response // response writer for server requests, else nil
}
// ErrBodyReadAfterClose is returned when reading a Request Body after
// the body has been closed. This typically happens when the body is
// ErrBodyReadAfterClose is returned when reading a Request or Response
// Body after the body has been closed. This typically happens when the body is
// read after an HTTP Handler calls WriteHeader or Write on its
// ResponseWriter.
var ErrBodyReadAfterClose = errors.New("http: invalid Read on closed request Body")
var ErrBodyReadAfterClose = errors.New("http: invalid Read on closed Body")
func (b *body) Read(p []byte) (n int, err error) {
if b.closed {
@ -641,3 +650,18 @@ func (b *body) Close() error {
}
return nil
}
// parseContentLength trims whitespace from s and returns -1 if no value
// is set, or the value if it's >= 0.
func parseContentLength(cl string) (int64, error) {
cl = strings.TrimSpace(cl)
if cl == "" {
return -1, nil
}
n, err := strconv.ParseInt(cl, 10, 64)
if err != nil || n < 0 {
return 0, &badStringError{"bad Content-Length", cl}
}
return n, nil
}

View File

@ -24,15 +24,14 @@ import (
"os"
"strings"
"sync"
"sync/atomic"
"time"
)
// DefaultTransport is the default implementation of Transport and is
// used by DefaultClient. It establishes a new network connection for
// each call to Do and uses HTTP proxies as directed by the
// $HTTP_PROXY and $NO_PROXY (or $http_proxy and $no_proxy)
// environment variables.
// used by DefaultClient. It establishes network connections as needed
// and caches them for reuse by subsequent calls. It uses HTTP proxies
// as directed by the $HTTP_PROXY and $NO_PROXY (or $http_proxy and
// $no_proxy) environment variables.
var DefaultTransport RoundTripper = &Transport{Proxy: ProxyFromEnvironment}
// DefaultMaxIdleConnsPerHost is the default value of Transport's
@ -71,7 +70,7 @@ type Transport struct {
DisableCompression bool
// MaxIdleConnsPerHost, if non-zero, controls the maximum idle
// (keep-alive) to keep to keep per-host. If zero,
// (keep-alive) to keep per-host. If zero,
// DefaultMaxIdleConnsPerHost is used.
MaxIdleConnsPerHost int
}
@ -91,7 +90,7 @@ func ProxyFromEnvironment(req *Request) (*url.URL, error) {
return nil, nil
}
proxyURL, err := url.Parse(proxy)
if err != nil || proxyURL.Scheme == "" {
if err != nil || !strings.HasPrefix(proxyURL.Scheme, "http") {
if u, err := url.Parse("http://" + proxy); err == nil {
proxyURL = u
err = nil
@ -605,22 +604,23 @@ func (pc *persistConn) readLoop() {
alive = false
}
// TODO(bradfitz): this hasBody conflicts with the defition
// above which excludes HEAD requests. Is this one
// incomplete?
hasBody := resp != nil && resp.ContentLength != 0
hasBody := resp != nil && rc.req.Method != "HEAD" && resp.ContentLength != 0
var waitForBodyRead chan bool
if hasBody {
lastbody = resp.Body
waitForBodyRead = make(chan bool, 1)
resp.Body.(*bodyEOFSignal).fn = func() {
if alive && !pc.t.putIdleConn(pc) {
alive = false
resp.Body.(*bodyEOFSignal).fn = func(err error) {
alive1 := alive
if err != nil {
alive1 = false
}
if !alive || pc.isBroken() {
if alive1 && !pc.t.putIdleConn(pc) {
alive1 = false
}
if !alive1 || pc.isBroken() {
pc.close()
}
waitForBodyRead <- true
waitForBodyRead <- alive1
}
}
@ -644,7 +644,7 @@ func (pc *persistConn) readLoop() {
// Wait for the just-returned response body to be fully consumed
// before we race and peek on the underlying bufio reader.
if waitForBodyRead != nil {
<-waitForBodyRead
alive = <-waitForBodyRead
}
if !alive {
@ -810,50 +810,61 @@ func canonicalAddr(url *url.URL) string {
}
// bodyEOFSignal wraps a ReadCloser but runs fn (if non-nil) at most
// once, right before the final Read() or Close() call returns, but after
// EOF has been seen.
// once, right before its final (error-producing) Read or Close call
// returns.
type bodyEOFSignal struct {
body io.ReadCloser
fn func()
isClosed uint32 // atomic bool, non-zero if true
once sync.Once
body io.ReadCloser
mu sync.Mutex // guards closed, rerr and fn
closed bool // whether Close has been called
rerr error // sticky Read error
fn func(error) // error will be nil on Read io.EOF
}
func (es *bodyEOFSignal) Read(p []byte) (n int, err error) {
n, err = es.body.Read(p)
if es.closed() && n > 0 {
panic("http: unexpected bodyEOFSignal Read after Close; see issue 1725")
es.mu.Lock()
closed, rerr := es.closed, es.rerr
es.mu.Unlock()
if closed {
return 0, errors.New("http: read on closed response body")
}
if err == io.EOF {
es.condfn()
if rerr != nil {
return 0, rerr
}
n, err = es.body.Read(p)
if err != nil {
es.mu.Lock()
defer es.mu.Unlock()
if es.rerr == nil {
es.rerr = err
}
es.condfn(err)
}
return
}
func (es *bodyEOFSignal) Close() (err error) {
if !es.setClosed() {
// already closed
func (es *bodyEOFSignal) Close() error {
es.mu.Lock()
defer es.mu.Unlock()
if es.closed {
return nil
}
err = es.body.Close()
if err == nil {
es.condfn()
es.closed = true
err := es.body.Close()
es.condfn(err)
return err
}
// caller must hold es.mu.
func (es *bodyEOFSignal) condfn(err error) {
if es.fn == nil {
return
}
return
}
func (es *bodyEOFSignal) condfn() {
if es.fn != nil {
es.once.Do(es.fn)
if err == io.EOF {
err = nil
}
}
func (es *bodyEOFSignal) closed() bool {
return atomic.LoadUint32(&es.isClosed) != 0
}
func (es *bodyEOFSignal) setClosed() bool {
return atomic.CompareAndSwapUint32(&es.isClosed, 0, 1)
es.fn(err)
es.fn = nil
}
type readFirstCloseBoth struct {

View File

@ -281,7 +281,7 @@ func TestTransportMaxPerHostIdleConns(t *testing.T) {
c := &Client{Transport: tr}
// Start 3 outstanding requests and wait for the server to get them.
// Their responses will hang until we we write to resch, though.
// Their responses will hang until we write to resch, though.
donech := make(chan bool)
doReq := func() {
resp, err := c.Get(ts.URL)
@ -464,7 +464,7 @@ func TestTransportHeadResponses(t *testing.T) {
if e, g := "123", res.Header.Get("Content-Length"); e != g {
t.Errorf("loop %d: expected Content-Length header of %q, got %q", i, e, g)
}
if e, g := int64(0), res.ContentLength; e != g {
if e, g := int64(123), res.ContentLength; e != g {
t.Errorf("loop %d: expected res.ContentLength of %v, got %v", i, e, g)
}
}
@ -857,6 +857,30 @@ func TestIssue3595(t *testing.T) {
}
}
// From http://golang.org/issue/4454 ,
// "client fails to handle requests with no body and chunked encoding"
func TestChunkedNoContent(t *testing.T) {
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.WriteHeader(StatusNoContent)
}))
defer ts.Close()
for _, closeBody := range []bool{true, false} {
c := &Client{Transport: &Transport{}}
const n = 4
for i := 1; i <= n; i++ {
res, err := c.Get(ts.URL)
if err != nil {
t.Errorf("closingBody=%v, req %d/%d: %v", closeBody, i, n, err)
} else {
if closeBody {
res.Body.Close()
}
}
}
}
}
func TestTransportConcurrency(t *testing.T) {
const maxProcs = 16
const numReqs = 500
@ -901,6 +925,113 @@ func TestTransportConcurrency(t *testing.T) {
wg.Wait()
}
func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
const debug = false
mux := NewServeMux()
mux.HandleFunc("/get", func(w ResponseWriter, r *Request) {
io.Copy(w, neverEnding('a'))
})
ts := httptest.NewServer(mux)
client := &Client{
Transport: &Transport{
Dial: func(n, addr string) (net.Conn, error) {
conn, err := net.Dial(n, addr)
if err != nil {
return nil, err
}
conn.SetDeadline(time.Now().Add(100 * time.Millisecond))
if debug {
conn = NewLoggingConn("client", conn)
}
return conn, nil
},
DisableKeepAlives: true,
},
}
nRuns := 5
if testing.Short() {
nRuns = 1
}
for i := 0; i < nRuns; i++ {
if debug {
println("run", i+1, "of", nRuns)
}
sres, err := client.Get(ts.URL + "/get")
if err != nil {
t.Errorf("Error issuing GET: %v", err)
break
}
_, err = io.Copy(ioutil.Discard, sres.Body)
if err == nil {
t.Errorf("Unexpected successful copy")
break
}
}
if debug {
println("tests complete; waiting for handlers to finish")
}
ts.Close()
}
func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) {
const debug = false
mux := NewServeMux()
mux.HandleFunc("/get", func(w ResponseWriter, r *Request) {
io.Copy(w, neverEnding('a'))
})
mux.HandleFunc("/put", func(w ResponseWriter, r *Request) {
defer r.Body.Close()
io.Copy(ioutil.Discard, r.Body)
})
ts := httptest.NewServer(mux)
client := &Client{
Transport: &Transport{
Dial: func(n, addr string) (net.Conn, error) {
conn, err := net.Dial(n, addr)
if err != nil {
return nil, err
}
conn.SetDeadline(time.Now().Add(100 * time.Millisecond))
if debug {
conn = NewLoggingConn("client", conn)
}
return conn, nil
},
DisableKeepAlives: true,
},
}
nRuns := 5
if testing.Short() {
nRuns = 1
}
for i := 0; i < nRuns; i++ {
if debug {
println("run", i+1, "of", nRuns)
}
sres, err := client.Get(ts.URL + "/get")
if err != nil {
t.Errorf("Error issuing GET: %v", err)
break
}
req, _ := NewRequest("PUT", ts.URL+"/put", sres.Body)
_, err = client.Do(req)
if err == nil {
sres.Body.Close()
t.Errorf("Unexpected successful PUT")
break
}
sres.Body.Close()
}
if debug {
println("tests complete; waiting for handlers to finish")
}
ts.Close()
}
type fooProto struct{}
func (fooProto) RoundTrip(req *Request) (*Response, error) {
@ -937,6 +1068,9 @@ var proxyFromEnvTests = []struct {
wanterr error
}{
{"127.0.0.1:8080", "http://127.0.0.1:8080", nil},
{"cache.corp.example.com:1234", "http://cache.corp.example.com:1234", nil},
{"cache.corp.example.com", "http://cache.corp.example.com", nil},
{"https://cache.corp.example.com", "https://cache.corp.example.com", nil},
{"http://127.0.0.1:8080", "http://127.0.0.1:8080", nil},
{"https://127.0.0.1:8080", "https://127.0.0.1:8080", nil},
{"", "<nil>", nil},

View File

@ -36,6 +36,7 @@ type IPMask []byte
type IPNet struct {
IP IP // network number
Mask IPMask // network mask
Zone string // IPv6 scoped addressing zone
}
// IPv4 returns the IP address (in 16-byte form) of the
@ -645,5 +646,5 @@ func ParseCIDR(s string) (IP, *IPNet, error) {
return nil, nil, &ParseError{"CIDR address", s}
}
m := CIDRMask(n, 8*iplen)
return ip, &IPNet{ip.Mask(m), m}, nil
return ip, &IPNet{IP: ip.Mask(m), Mask: m}, nil
}

View File

@ -114,23 +114,23 @@ var parsecidrtests = []struct {
net *IPNet
err error
}{
{"135.104.0.0/32", IPv4(135, 104, 0, 0), &IPNet{IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 255)}, nil},
{"0.0.0.0/24", IPv4(0, 0, 0, 0), &IPNet{IPv4(0, 0, 0, 0), IPv4Mask(255, 255, 255, 0)}, nil},
{"135.104.0.0/24", IPv4(135, 104, 0, 0), &IPNet{IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 0)}, nil},
{"135.104.0.1/32", IPv4(135, 104, 0, 1), &IPNet{IPv4(135, 104, 0, 1), IPv4Mask(255, 255, 255, 255)}, nil},
{"135.104.0.1/24", IPv4(135, 104, 0, 1), &IPNet{IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 0)}, nil},
{"::1/128", ParseIP("::1"), &IPNet{ParseIP("::1"), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))}, nil},
{"abcd:2345::/127", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe"))}, nil},
{"abcd:2345::/65", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff:8000::"))}, nil},
{"abcd:2345::/64", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff::"))}, nil},
{"abcd:2345::/63", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:fffe::"))}, nil},
{"abcd:2345::/33", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:8000::"))}, nil},
{"abcd:2345::/32", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff::"))}, nil},
{"abcd:2344::/31", ParseIP("abcd:2344::"), &IPNet{ParseIP("abcd:2344::"), IPMask(ParseIP("ffff:fffe::"))}, nil},
{"abcd:2300::/24", ParseIP("abcd:2300::"), &IPNet{ParseIP("abcd:2300::"), IPMask(ParseIP("ffff:ff00::"))}, nil},
{"abcd:2345::/24", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2300::"), IPMask(ParseIP("ffff:ff00::"))}, nil},
{"2001:DB8::/48", ParseIP("2001:DB8::"), &IPNet{ParseIP("2001:DB8::"), IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
{"2001:DB8::1/48", ParseIP("2001:DB8::1"), &IPNet{ParseIP("2001:DB8::"), IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
{"135.104.0.0/32", IPv4(135, 104, 0, 0), &IPNet{IP: IPv4(135, 104, 0, 0), Mask: IPv4Mask(255, 255, 255, 255)}, nil},
{"0.0.0.0/24", IPv4(0, 0, 0, 0), &IPNet{IP: IPv4(0, 0, 0, 0), Mask: IPv4Mask(255, 255, 255, 0)}, nil},
{"135.104.0.0/24", IPv4(135, 104, 0, 0), &IPNet{IP: IPv4(135, 104, 0, 0), Mask: IPv4Mask(255, 255, 255, 0)}, nil},
{"135.104.0.1/32", IPv4(135, 104, 0, 1), &IPNet{IP: IPv4(135, 104, 0, 1), Mask: IPv4Mask(255, 255, 255, 255)}, nil},
{"135.104.0.1/24", IPv4(135, 104, 0, 1), &IPNet{IP: IPv4(135, 104, 0, 0), Mask: IPv4Mask(255, 255, 255, 0)}, nil},
{"::1/128", ParseIP("::1"), &IPNet{IP: ParseIP("::1"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))}, nil},
{"abcd:2345::/127", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe"))}, nil},
{"abcd:2345::/65", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:8000::"))}, nil},
{"abcd:2345::/64", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff::"))}, nil},
{"abcd:2345::/63", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:fffe::"))}, nil},
{"abcd:2345::/33", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:8000::"))}, nil},
{"abcd:2345::/32", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff::"))}, nil},
{"abcd:2344::/31", ParseIP("abcd:2344::"), &IPNet{IP: ParseIP("abcd:2344::"), Mask: IPMask(ParseIP("ffff:fffe::"))}, nil},
{"abcd:2300::/24", ParseIP("abcd:2300::"), &IPNet{IP: ParseIP("abcd:2300::"), Mask: IPMask(ParseIP("ffff:ff00::"))}, nil},
{"abcd:2345::/24", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2300::"), Mask: IPMask(ParseIP("ffff:ff00::"))}, nil},
{"2001:DB8::/48", ParseIP("2001:DB8::"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
{"2001:DB8::1/48", ParseIP("2001:DB8::1"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
{"192.168.1.1/255.255.255.0", nil, nil, &ParseError{"CIDR address", "192.168.1.1/255.255.255.0"}},
{"192.168.1.1/35", nil, nil, &ParseError{"CIDR address", "192.168.1.1/35"}},
{"2001:db8::1/-1", nil, nil, &ParseError{"CIDR address", "2001:db8::1/-1"}},
@ -154,14 +154,14 @@ var ipnetcontainstests = []struct {
net *IPNet
ok bool
}{
{IPv4(172, 16, 1, 1), &IPNet{IPv4(172, 16, 0, 0), CIDRMask(12, 32)}, true},
{IPv4(172, 24, 0, 1), &IPNet{IPv4(172, 16, 0, 0), CIDRMask(13, 32)}, false},
{IPv4(192, 168, 0, 3), &IPNet{IPv4(192, 168, 0, 0), IPv4Mask(0, 0, 255, 252)}, true},
{IPv4(192, 168, 0, 4), &IPNet{IPv4(192, 168, 0, 0), IPv4Mask(0, 255, 0, 252)}, false},
{ParseIP("2001:db8:1:2::1"), &IPNet{ParseIP("2001:db8:1::"), CIDRMask(47, 128)}, true},
{ParseIP("2001:db8:1:2::1"), &IPNet{ParseIP("2001:db8:2::"), CIDRMask(47, 128)}, false},
{ParseIP("2001:db8:1:2::1"), &IPNet{ParseIP("2001:db8:1::"), IPMask(ParseIP("ffff:0:ffff::"))}, true},
{ParseIP("2001:db8:1:2::1"), &IPNet{ParseIP("2001:db8:1::"), IPMask(ParseIP("0:0:0:ffff::"))}, false},
{IPv4(172, 16, 1, 1), &IPNet{IP: IPv4(172, 16, 0, 0), Mask: CIDRMask(12, 32)}, true},
{IPv4(172, 24, 0, 1), &IPNet{IP: IPv4(172, 16, 0, 0), Mask: CIDRMask(13, 32)}, false},
{IPv4(192, 168, 0, 3), &IPNet{IP: IPv4(192, 168, 0, 0), Mask: IPv4Mask(0, 0, 255, 252)}, true},
{IPv4(192, 168, 0, 4), &IPNet{IP: IPv4(192, 168, 0, 0), Mask: IPv4Mask(0, 255, 0, 252)}, false},
{ParseIP("2001:db8:1:2::1"), &IPNet{IP: ParseIP("2001:db8:1::"), Mask: CIDRMask(47, 128)}, true},
{ParseIP("2001:db8:1:2::1"), &IPNet{IP: ParseIP("2001:db8:2::"), Mask: CIDRMask(47, 128)}, false},
{ParseIP("2001:db8:1:2::1"), &IPNet{IP: ParseIP("2001:db8:1::"), Mask: IPMask(ParseIP("ffff:0:ffff::"))}, true},
{ParseIP("2001:db8:1:2::1"), &IPNet{IP: ParseIP("2001:db8:1::"), Mask: IPMask(ParseIP("0:0:0:ffff::"))}, false},
}
func TestIPNetContains(t *testing.T) {
@ -176,10 +176,10 @@ var ipnetstringtests = []struct {
in *IPNet
out string
}{
{&IPNet{IPv4(192, 168, 1, 0), CIDRMask(26, 32)}, "192.168.1.0/26"},
{&IPNet{IPv4(192, 168, 1, 0), IPv4Mask(255, 0, 255, 0)}, "192.168.1.0/ff00ff00"},
{&IPNet{ParseIP("2001:db8::"), CIDRMask(55, 128)}, "2001:db8::/55"},
{&IPNet{ParseIP("2001:db8::"), IPMask(ParseIP("8000:f123:0:cafe::"))}, "2001:db8::/8000f1230000cafe0000000000000000"},
{&IPNet{IP: IPv4(192, 168, 1, 0), Mask: CIDRMask(26, 32)}, "192.168.1.0/26"},
{&IPNet{IP: IPv4(192, 168, 1, 0), Mask: IPv4Mask(255, 0, 255, 0)}, "192.168.1.0/ff00ff00"},
{&IPNet{IP: ParseIP("2001:db8::"), Mask: CIDRMask(55, 128)}, "2001:db8::/55"},
{&IPNet{IP: ParseIP("2001:db8::"), Mask: IPMask(ParseIP("8000:f123:0:cafe::"))}, "2001:db8::/8000f1230000cafe0000000000000000"},
}
func TestIPNetString(t *testing.T) {
@ -233,27 +233,27 @@ var networknumberandmasktests = []struct {
in IPNet
out IPNet
}{
{IPNet{v4addr, v4mask}, IPNet{v4addr, v4mask}},
{IPNet{v4addr, v4mappedv6mask}, IPNet{v4addr, v4mask}},
{IPNet{v4mappedv6addr, v4mappedv6mask}, IPNet{v4addr, v4mask}},
{IPNet{v4mappedv6addr, v6mask}, IPNet{v4addr, v4maskzero}},
{IPNet{v4addr, v6mask}, IPNet{v4addr, v4maskzero}},
{IPNet{v6addr, v6mask}, IPNet{v6addr, v6mask}},
{IPNet{v6addr, v4mappedv6mask}, IPNet{v6addr, v4mappedv6mask}},
{in: IPNet{v6addr, v4mask}},
{in: IPNet{v4addr, badmask}},
{in: IPNet{v4mappedv6addr, badmask}},
{in: IPNet{v6addr, badmask}},
{in: IPNet{badaddr, v4mask}},
{in: IPNet{badaddr, v4mappedv6mask}},
{in: IPNet{badaddr, v6mask}},
{in: IPNet{badaddr, badmask}},
{IPNet{IP: v4addr, Mask: v4mask}, IPNet{IP: v4addr, Mask: v4mask}},
{IPNet{IP: v4addr, Mask: v4mappedv6mask}, IPNet{IP: v4addr, Mask: v4mask}},
{IPNet{IP: v4mappedv6addr, Mask: v4mappedv6mask}, IPNet{IP: v4addr, Mask: v4mask}},
{IPNet{IP: v4mappedv6addr, Mask: v6mask}, IPNet{IP: v4addr, Mask: v4maskzero}},
{IPNet{IP: v4addr, Mask: v6mask}, IPNet{IP: v4addr, Mask: v4maskzero}},
{IPNet{IP: v6addr, Mask: v6mask}, IPNet{IP: v6addr, Mask: v6mask}},
{IPNet{IP: v6addr, Mask: v4mappedv6mask}, IPNet{IP: v6addr, Mask: v4mappedv6mask}},
{in: IPNet{IP: v6addr, Mask: v4mask}},
{in: IPNet{IP: v4addr, Mask: badmask}},
{in: IPNet{IP: v4mappedv6addr, Mask: badmask}},
{in: IPNet{IP: v6addr, Mask: badmask}},
{in: IPNet{IP: badaddr, Mask: v4mask}},
{in: IPNet{IP: badaddr, Mask: v4mappedv6mask}},
{in: IPNet{IP: badaddr, Mask: v6mask}},
{in: IPNet{IP: badaddr, Mask: badmask}},
}
func TestNetworkNumberAndMask(t *testing.T) {
for _, tt := range networknumberandmasktests {
ip, m := networkNumberAndMask(&tt.in)
out := &IPNet{ip, m}
out := &IPNet{IP: ip, Mask: m}
if !reflect.DeepEqual(&tt.out, out) {
t.Errorf("networkNumberAndMask(%v) = %v; want %v", tt.in, out, &tt.out)
}
@ -268,6 +268,7 @@ var splitjointests = []struct {
{"www.google.com", "80", "www.google.com:80"},
{"127.0.0.1", "1234", "127.0.0.1:1234"},
{"::1", "80", "[::1]:80"},
{"google.com", "https%foo", "google.com:https%foo"}, // Go 1.0 behavior
}
func TestSplitHostPort(t *testing.T) {

View File

@ -9,11 +9,46 @@ package net
import (
"bytes"
"os"
"reflect"
"syscall"
"testing"
"time"
)
var resolveIPAddrTests = []struct {
net string
litAddr string
addr *IPAddr
err error
}{
{"ip", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
{"ip4", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
{"ip4:icmp", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
{"ip", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
{"ip6", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
{"ip6:icmp", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
{"", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil}, // Go 1.0 behavior
{"", "::1", &IPAddr{IP: ParseIP("::1")}, nil}, // Go 1.0 behavior
{"l2tp", "127.0.0.1", nil, UnknownNetworkError("l2tp")},
{"l2tp:gre", "127.0.0.1", nil, UnknownNetworkError("l2tp:gre")},
{"tcp", "1.2.3.4:123", nil, UnknownNetworkError("tcp")},
}
func TestResolveIPAddr(t *testing.T) {
for _, tt := range resolveIPAddrTests {
addr, err := ResolveIPAddr(tt.net, tt.litAddr)
if err != tt.err {
t.Fatalf("ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err)
}
if !reflect.DeepEqual(addr, tt.addr) {
t.Fatalf("got %#v; expected %#v", addr, tt.addr)
}
}
}
var icmpTests = []struct {
net string
laddr string

View File

@ -2,17 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// (Raw) IP sockets
// Raw IP sockets
package net
import (
"time"
)
// IPAddr represents the address of an IP end point.
type IPAddr struct {
IP IP
IP IP
Zone string // IPv6 scoped addressing zone
}
// Network returns the address's network name, "ip".
@ -27,47 +24,23 @@ func (a *IPAddr) String() string {
// ResolveIPAddr parses addr as an IP address and resolves domain
// names to numeric addresses on the network net, which must be
// "ip", "ip4" or "ip6". A literal IPv6 host address must be
// enclosed in square brackets, as in "[::]".
// "ip", "ip4" or "ip6".
func ResolveIPAddr(net, addr string) (*IPAddr, error) {
return resolveIPAddr(net, addr, noDeadline)
}
func resolveIPAddr(net, addr string, deadline time.Time) (*IPAddr, error) {
ip, err := hostToIP(net, addr, deadline)
if net == "" { // a hint wildcard for Go 1.0 undocumented behavior
net = "ip"
}
afnet, _, err := parseDialNetwork(net)
if err != nil {
return nil, err
}
return &IPAddr{ip}, nil
}
// Convert "host" into IP address.
func hostToIP(net, host string, deadline time.Time) (ip IP, err error) {
var addr IP
// Try as an IP address.
addr = ParseIP(host)
if addr == nil {
filter := anyaddr
if net != "" && net[len(net)-1] == '4' {
filter = ipv4only
}
if net != "" && net[len(net)-1] == '6' {
filter = ipv6only
}
// Not an IP address. Try as a DNS name.
addrs, err1 := lookupHostDeadline(host, deadline)
if err1 != nil {
err = err1
goto Error
}
addr = firstFavoriteAddr(filter, addrs)
if addr == nil {
// should not happen
err = &AddrError{"LookupHost returned no suitable address", addrs[0]}
goto Error
}
switch afnet {
case "ip", "ip4", "ip6":
default:
return nil, UnknownNetworkError(net)
}
return addr, nil
Error:
return nil, err
a, err := resolveInternetAddr(afnet, addr, noDeadline)
if err != nil {
return nil, err
}
return a.(*IPAddr), nil
}

View File

@ -2,83 +2,21 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// (Raw) IP sockets stubs for Plan 9
// Raw IP sockets for Plan 9
package net
import (
"os"
"syscall"
"time"
)
// IPConn is the implementation of the Conn and PacketConn interfaces
// for IP network connections.
type IPConn bool
// Implementation of the Conn interface - see Conn for documentation.
// Read implements the Conn Read method.
func (c *IPConn) Read(b []byte) (int, error) {
return 0, syscall.EPLAN9
type IPConn struct {
conn
}
// Write implements the Conn Write method.
func (c *IPConn) Write(b []byte) (int, error) {
return 0, syscall.EPLAN9
}
// LocalAddr returns the local network address.
func (c *IPConn) LocalAddr() Addr {
return nil
}
// RemoteAddr returns the remote network address.
func (c *IPConn) RemoteAddr() Addr {
return nil
}
// SetDeadline implements the Conn SetDeadline method.
func (c *IPConn) SetDeadline(t time.Time) error {
return syscall.EPLAN9
}
// SetReadDeadline implements the Conn SetReadDeadline method.
func (c *IPConn) SetReadDeadline(t time.Time) error {
return syscall.EPLAN9
}
// SetWriteDeadline implements the Conn SetWriteDeadline method.
func (c *IPConn) SetWriteDeadline(t time.Time) error {
return syscall.EPLAN9
}
// SetReadBuffer sets the size of the operating system's receive
// buffer associated with the connection.
func (c *IPConn) SetReadBuffer(bytes int) error {
return syscall.EPLAN9
}
// SetWriteBuffer sets the size of the operating system's transmit
// buffer associated with the connection.
func (c *IPConn) SetWriteBuffer(bytes int) error {
return syscall.EPLAN9
}
// File returns a copy of the underlying os.File, set to blocking
// mode. It is the caller's responsibility to close f when finished.
// Closing c does not affect f, and closing f does not affect c.
func (c *IPConn) File() (f *os.File, err error) {
return nil, syscall.EPLAN9
}
// Close closes the IP connection.
func (c *IPConn) Close() error {
return syscall.EPLAN9
}
// IP-specific methods.
// ReadFromIP reads an IP packet from c, copying the payload into b.
// It returns the number of bytes copied into b and the return address
// that was on the packet.

View File

@ -4,7 +4,7 @@
// +build darwin freebsd linux netbsd openbsd windows
// (Raw) IP sockets
// Raw IP sockets for POSIX
package net
@ -16,9 +16,9 @@ import (
func sockaddrToIP(sa syscall.Sockaddr) Addr {
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
return &IPAddr{sa.Addr[0:]}
return &IPAddr{IP: sa.Addr[0:]}
case *syscall.SockaddrInet6:
return &IPAddr{sa.Addr[0:]}
return &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
}
return nil
}
@ -41,7 +41,7 @@ func (a *IPAddr) isWildcard() bool {
}
func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, 0)
return ipToSockaddr(family, a.IP, 0, a.Zone)
}
func (a *IPAddr) toAddr() sockaddr {
@ -59,8 +59,6 @@ type IPConn struct {
func newIPConn(fd *netFD) *IPConn { return &IPConn{conn{fd}} }
// IP-specific methods.
// ReadFromIP reads an IP packet from c, copying the payload into b.
// It returns the number of bytes copied into b and the return address
// that was on the packet.
@ -78,14 +76,14 @@ func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
n, sa, err := c.fd.ReadFrom(b)
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
addr = &IPAddr{sa.Addr[0:]}
addr = &IPAddr{IP: sa.Addr[0:]}
if len(b) >= IPv4len { // discard ipv4 header
hsize := (int(b[0]) & 0xf) * 4
copy(b, b[hsize:])
n -= hsize
}
case *syscall.SockaddrInet6:
addr = &IPAddr{sa.Addr[0:]}
addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
}
return n, addr, err
}
@ -95,8 +93,8 @@ func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
if !c.ok() {
return 0, nil, syscall.EINVAL
}
n, uaddr, err := c.ReadFromIP(b)
return n, uaddr.toAddr(), err
n, addr, err := c.ReadFromIP(b)
return n, addr.toAddr(), err
}
// ReadMsgIP reads a packet from c, copying the payload into b and the
@ -111,9 +109,9 @@ func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err
n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
addr = &IPAddr{sa.Addr[0:]}
addr = &IPAddr{IP: sa.Addr[0:]}
case *syscall.SockaddrInet6:
addr = &IPAddr{sa.Addr[0:]}
addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
}
return
}

View 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.
// IP sockets
// Internet protocol family sockets
package net
@ -72,15 +72,18 @@ func (e InvalidAddrError) Temporary() bool { return false }
// "host:port" or "[host]:port" into host and port.
// The latter form must be used when host contains a colon.
func SplitHostPort(hostport string) (host, port string, err error) {
host, port, _, err = splitHostPort(hostport)
return
}
func splitHostPort(hostport string) (host, port, zone string, err error) {
// The port starts after the last colon.
i := last(hostport, ':')
if i < 0 {
err = &AddrError{"missing port in address", hostport}
return
}
host, port = hostport[0:i], hostport[i+1:]
host, port = hostport[:i], hostport[i+1:]
// Can put brackets around host ...
if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
host = host[1 : len(host)-1]
@ -104,42 +107,84 @@ func JoinHostPort(host, port string) string {
return host + ":" + port
}
// Convert "host:port" into IP address and port.
func hostPortToIP(net, hostport string, deadline time.Time) (ip IP, iport int, err error) {
host, port, err := SplitHostPort(hostport)
if err != nil {
return nil, 0, err
}
var addr IP
if host != "" {
// Try as an IP address.
addr = ParseIP(host)
if addr == nil {
var filter func(IP) IP
if net != "" && net[len(net)-1] == '4' {
filter = ipv4only
func resolveInternetAddr(net, addr string, deadline time.Time) (Addr, error) {
var (
err error
host, port, zone string
portnum int
)
switch net {
case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
if addr != "" {
if host, port, zone, err = splitHostPort(addr); err != nil {
return nil, err
}
if net != "" && net[len(net)-1] == '6' {
filter = ipv6only
}
// Not an IP address. Try as a DNS name.
addrs, err := lookupHostDeadline(host, deadline)
if err != nil {
return nil, 0, err
}
addr = firstFavoriteAddr(filter, addrs)
if addr == nil {
// should not happen
return nil, 0, &AddrError{"LookupHost returned no suitable address", addrs[0]}
if portnum, err = parsePort(net, port); err != nil {
return nil, err
}
}
case "ip", "ip4", "ip6":
if addr != "" {
host = addr
}
default:
return nil, UnknownNetworkError(net)
}
p, err := parsePort(net, port)
inetaddr := func(net string, ip IP, port int, zone string) Addr {
switch net {
case "tcp", "tcp4", "tcp6":
return &TCPAddr{IP: ip, Port: port, Zone: zone}
case "udp", "udp4", "udp6":
return &UDPAddr{IP: ip, Port: port, Zone: zone}
case "ip", "ip4", "ip6":
return &IPAddr{IP: ip, Zone: zone}
}
return nil
}
if host == "" {
return inetaddr(net, nil, portnum, zone), nil
}
// Try as an IP address.
if ip := ParseIP(host); ip != nil {
return inetaddr(net, ip, portnum, zone), nil
}
var filter func(IP) IP
if net != "" && net[len(net)-1] == '4' {
filter = ipv4only
}
if net != "" && net[len(net)-1] == '6' {
filter = ipv6only
}
// Try as a DNS name.
addrs, err := lookupHostDeadline(host, deadline)
if err != nil {
return nil, 0, err
return nil, err
}
return addr, p, nil
ip := firstFavoriteAddr(filter, addrs)
if ip == nil {
// should not happen
return nil, &AddrError{"LookupHost returned no suitable address", addrs[0]}
}
return inetaddr(net, ip, portnum, zone), nil
}
func zoneToString(zone int) string {
if zone == 0 {
return ""
}
if ifi, err := InterfaceByIndex(zone); err == nil {
return ifi.Name
}
return itod(uint(zone))
}
func zoneToInt(zone string) int {
if zone == "" {
return 0
}
if ifi, err := InterfaceByName(zone); err == nil {
return ifi.Index
}
n, _, _ := dtoi(zone, 0)
return n
}

View 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.
// IP sockets stubs for Plan 9
// Internet protocol family sockets for Plan 9
package net
@ -59,9 +59,9 @@ func readPlan9Addr(proto, filename string) (addr Addr, err error) {
}
switch proto {
case "tcp":
addr = &TCPAddr{ip, port}
addr = &TCPAddr{IP: ip, Port: port}
case "udp":
addr = &UDPAddr{ip, port}
addr = &UDPAddr{IP: ip, Port: port}
default:
return nil, errors.New("unknown protocol " + proto)
}

View File

@ -4,6 +4,8 @@
// +build darwin freebsd linux netbsd openbsd windows
// Internet protocol family sockets for POSIX
package net
import (
@ -155,7 +157,7 @@ Error:
return nil, &OpError{mode, net, addr, err}
}
func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, error) {
func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, error) {
switch family {
case syscall.AF_INET:
if len(ip) == 0 {
@ -164,12 +166,12 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, error) {
if ip = ip.To4(); ip == nil {
return nil, InvalidAddrError("non-IPv4 address")
}
s := new(syscall.SockaddrInet4)
sa := new(syscall.SockaddrInet4)
for i := 0; i < IPv4len; i++ {
s.Addr[i] = ip[i]
sa.Addr[i] = ip[i]
}
s.Port = port
return s, nil
sa.Port = port
return sa, nil
case syscall.AF_INET6:
if len(ip) == 0 {
ip = IPv6zero
@ -183,12 +185,13 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, error) {
if ip = ip.To16(); ip == nil {
return nil, InvalidAddrError("non-IPv6 address")
}
s := new(syscall.SockaddrInet6)
sa := new(syscall.SockaddrInet6)
for i := 0; i < IPv6len; i++ {
s.Addr[i] = ip[i]
sa.Addr[i] = ip[i]
}
s.Port = port
return s, nil
sa.Port = port
sa.ZoneId = uint32(zoneToInt(zone))
return sa, nil
}
return nil, InvalidAddrError("unexpected socket family")
}

View File

@ -21,26 +21,26 @@ var multicastListenerTests = []struct {
}{
// cf. RFC 4727: Experimental Values in IPv4, IPv6, ICMPv4, ICMPv6, UDP, and TCP Headers
{"udp", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
{"udp", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, 0, false},
{"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
{"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, 0, true},
{"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, FlagUp | FlagLoopback, false},
{"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, 0, false},
{"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, FlagUp | FlagLoopback, true},
{"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, 0, true},
{"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
{"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, 0, false},
{"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, FlagUp | FlagLoopback, false},
{"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, 0, false},
{"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, FlagUp | FlagLoopback, true},
{"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, 0, true},
{"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, FlagUp | FlagLoopback, true},
{"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, 0, true},
{"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, FlagUp | FlagLoopback, true},
{"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, 0, true},
{"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, FlagUp | FlagLoopback, true},
{"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, 0, true},
{"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, FlagUp | FlagLoopback, true},
{"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, 0, true},
{"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
{"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, 0, true},
{"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}, FlagUp | FlagLoopback, true},
{"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}, 0, true},
{"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}, FlagUp | FlagLoopback, true},
{"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}, 0, true},
{"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}, FlagUp | FlagLoopback, true},
{"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}, 0, true},
{"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}, FlagUp | FlagLoopback, true},
{"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}, 0, true},
{"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}, FlagUp | FlagLoopback, true},
{"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}, 0, true},
{"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, FlagUp | FlagLoopback, true},
{"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, 0, true},
}
// TestMulticastListener tests both single and double listen to a test

View File

@ -44,7 +44,9 @@ package net
import (
"errors"
"io"
"os"
"sync"
"syscall"
"time"
)
@ -195,9 +197,13 @@ func (c *conn) SetWriteBuffer(bytes int) error {
return setWriteBuffer(c.fd, bytes)
}
// File returns a copy of the underlying os.File, set to blocking mode.
// File sets the underlying os.File to blocking mode and returns a copy.
// It is the caller's responsibility to close f when finished.
// Closing c does not affect f, and closing f does not affect c.
//
// The returned os.File's file descriptor is different from the connection's.
// Attempting to change properties of the original using this duplicate
// may or may not have the desired effect.
func (c *conn) File() (f *os.File, err error) { return c.fd.dup() }
// An Error represents a network error.
@ -363,3 +369,47 @@ func (e *DNSConfigError) Error() string {
func (e *DNSConfigError) Timeout() bool { return false }
func (e *DNSConfigError) Temporary() bool { return false }
type writerOnly struct {
io.Writer
}
// Fallback implementation of io.ReaderFrom's ReadFrom, when sendfile isn't
// applicable.
func genericReadFrom(w io.Writer, r io.Reader) (n int64, err error) {
// Use wrapper to hide existing r.ReadFrom from io.Copy.
return io.Copy(writerOnly{w}, r)
}
// deadline is an atomically-accessed number of nanoseconds since 1970
// or 0, if no deadline is set.
type deadline struct {
sync.Mutex
val int64
}
func (d *deadline) expired() bool {
t := d.value()
return t > 0 && time.Now().UnixNano() >= t
}
func (d *deadline) value() (v int64) {
d.Lock()
v = d.val
d.Unlock()
return
}
func (d *deadline) set(v int64) {
d.Lock()
d.val = v
d.Unlock()
}
func (d *deadline) setTime(t time.Time) {
if t.IsZero() {
d.set(0)
} else {
d.set(t.UnixNano())
}
}

View File

@ -112,7 +112,7 @@
// Asynchronous call
quotient := new(Quotient)
divCall := client.Go("Arith.Divide", args, &quotient, nil)
divCall := client.Go("Arith.Divide", args, quotient, nil)
replyCall := <-divCall.Done // will be equal to divCall
// check errors, print, etc.
@ -219,8 +219,8 @@ func isExportedOrBuiltinType(t reflect.Type) bool {
// - exported method
// - two arguments, both pointers to exported structs
// - one return value, of type error
// It returns an error if the receiver is not an exported type or has no
// suitable methods.
// It returns an error if the receiver is not an exported type or has
// no methods or unsuitable methods. It also logs the error using package log.
// The client accesses each method using a string of the form "Type.Method",
// where Type is the receiver's concrete type.
func (server *Server) Register(rcvr interface{}) error {

Some files were not shown because too many files have changed in this diff Show More