libgo: Update to current master library sources.
From-SVN: r194460
This commit is contained in:
parent
bc77608b97
commit
a42a906c42
145 changed files with 6245 additions and 1920 deletions
|
@ -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.
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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{} {
|
||||
|
|
|
@ -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.
|
||||
//
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")}
|
||||
|
|
|
@ -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
|
||||
|
|
89
libgo/go/exp/cookiejar/jar.go
Normal file
89
libgo/go/exp/cookiejar/jar.go
Normal 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.
|
||||
}
|
101
libgo/go/exp/cookiejar/storage.go
Normal file
101
libgo/go/exp/cookiejar/storage.go
Normal 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
|
||||
}
|
48
libgo/go/exp/cookiejar/storage_test.go
Normal file
48
libgo/go/exp/cookiejar/storage_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
2
libgo/go/exp/gotype/testdata/test1.go
vendored
2
libgo/go/exp/gotype/testdata/test1.go
vendored
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"}},
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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] = ©
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
13
libgo/go/exp/types/testdata/decls0.src
vendored
13
libgo/go/exp/types/testdata/decls0.src
vendored
|
@ -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
|
||||
|
|
2
libgo/go/exp/types/testdata/decls1.src
vendored
2
libgo/go/exp/types/testdata/decls1.src
vendored
|
@ -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)
|
||||
|
|
236
libgo/go/exp/types/testdata/expr3.src
vendored
236
libgo/go/exp/types/testdata/expr3.src
vendored
|
@ -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" */ )
|
||||
}
|
||||
|
|
166
libgo/go/exp/types/testdata/stmt0.src
vendored
166
libgo/go/exp/types/testdata/stmt0.src
vendored
|
@ -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 {}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
200
libgo/go/go/format/format.go
Normal file
200
libgo/go/go/format/format.go
Normal 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
|
||||
}
|
125
libgo/go/go/format/format_test.go
Normal file
125
libgo/go/go/format/format_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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).
|
||||
//
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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) {
|
||||
|
|
82
libgo/go/go/printer/testdata/statements.golden
vendored
82
libgo/go/go/printer/testdata/statements.golden
vendored
|
@ -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
|
||||
|
|
62
libgo/go/go/printer/testdata/statements.input
vendored
62
libgo/go/go/printer/testdata/statements.input
vendored
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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, ×tamp, &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, ×tamp, &parsedHostname, &pid); n != 3 ||
|
||||
err != nil || hostname != parsedHostname {
|
||||
t.Fatalf("s.Info() = '%q', didn't match '%q'", rcvd, test.exp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
}()
|
||||
|
|
|
@ -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
|
||||
|
|
92
libgo/go/mime/multipart/quotedprintable.go
Normal file
92
libgo/go/mime/multipart/quotedprintable.go
Normal 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
|
||||
}
|
52
libgo/go/mime/multipart/quotedprintable_test.go
Normal file
52
libgo/go/mime/multipart/quotedprintable_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
57
libgo/go/net/fd_posix_test.go
Normal file
57
libgo/go/net/fd_posix_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
77
libgo/go/net/http/cgi/testdata/test.cgi
vendored
77
libgo/go/net/http/cgi/testdata/test.cgi
vendored
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -193,7 +193,7 @@ var respTests = []respTest{
|
|||
Request: dummyReq("HEAD"),
|
||||
Header: Header{},
|
||||
Close: true,
|
||||
ContentLength: 0,
|
||||
ContentLength: -1,
|
||||
},
|
||||
|
||||
"",
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@
|
|||
|
||||
// Asynchronous call
|
||||
quotient := new(Quotient)
|
||||
divCall := client.Go("Arith.Divide", args, "ient, 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
Loading…
Add table
Reference in a new issue