diff options
Diffstat (limited to 'libgo/go/net')
43 files changed, 796 insertions, 467 deletions
diff --git a/libgo/go/net/cgo_unix.go b/libgo/go/net/cgo_unix.go index 680d3e7..1a0f406 100644 --- a/libgo/go/net/cgo_unix.go +++ b/libgo/go/net/cgo_unix.go @@ -109,7 +109,7 @@ func cgoLookupIPCNAME(name string) (addrs []IP, cname string, err error, complet if gerrno == syscall.EAI_NONAME { str = noSuchHost } else if gerrno == syscall.EAI_SYSTEM { - str = syscall.Errstr(syscall.GetErrno()) + str = syscall.GetErrno().Error() } else { str = bytePtrToString(libc_gai_strerror(gerrno)) } diff --git a/libgo/go/net/fd.go b/libgo/go/net/fd.go index 025075d..70e04a2 100644 --- a/libgo/go/net/fd.go +++ b/libgo/go/net/fd.go @@ -278,8 +278,8 @@ func startServer() { func newFD(fd, family, proto int, net string) (f *netFD, err error) { onceStartServer.Do(startServer) - if e := syscall.SetNonblock(fd, true); e != 0 { - return nil, os.Errno(e) + if e := syscall.SetNonblock(fd, true); e != nil { + return nil, e } f = &netFD{ sysfd: fd, @@ -306,19 +306,19 @@ func (fd *netFD) setAddr(laddr, raddr Addr) { } func (fd *netFD) connect(ra syscall.Sockaddr) (err error) { - e := syscall.Connect(fd.sysfd, ra) - if e == syscall.EINPROGRESS { - var errno int + err = syscall.Connect(fd.sysfd, ra) + if err == syscall.EINPROGRESS { pollserver.WaitWrite(fd) - e, errno = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR) - if errno != 0 { - return os.NewSyscallError("getsockopt", errno) + var e int + e, err = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR) + if err != nil { + return os.NewSyscallError("getsockopt", err) + } + if e != 0 { + err = syscall.Errno(e) } } - if e != 0 { - return os.Errno(e) - } - return nil + return err } // Add a reference to this fd. @@ -362,9 +362,9 @@ func (fd *netFD) shutdown(how int) error { if fd == nil || fd.sysfile == nil { return os.EINVAL } - errno := syscall.Shutdown(fd.sysfd, how) - if errno != 0 { - return &OpError{"shutdown", fd.net, fd.laddr, os.Errno(errno)} + err := syscall.Shutdown(fd.sysfd, how) + if err != nil { + return &OpError{"shutdown", fd.net, fd.laddr, err} } return nil } @@ -377,6 +377,14 @@ func (fd *netFD) CloseWrite() error { return fd.shutdown(syscall.SHUT_WR) } +type timeoutError struct{} + +func (e *timeoutError) Error() string { return "i/o timeout" } +func (e *timeoutError) Timeout() bool { return true } +func (e *timeoutError) Temporary() bool { return true } + +var errTimeout error = &timeoutError{} + func (fd *netFD) Read(p []byte) (n int, err error) { if fd == nil { return 0, os.EINVAL @@ -393,24 +401,24 @@ func (fd *netFD) Read(p []byte) (n int, err error) { } else { fd.rdeadline = 0 } - var oserr error for { - var errno int - n, errno = syscall.Read(fd.sysfile.Fd(), p) - if errno == syscall.EAGAIN && fd.rdeadline >= 0 { - pollserver.WaitRead(fd) - continue + n, err = syscall.Read(fd.sysfile.Fd(), p) + if err == syscall.EAGAIN { + if fd.rdeadline >= 0 { + pollserver.WaitRead(fd) + continue + } + err = errTimeout } - if errno != 0 { + if err != nil { n = 0 - oserr = os.Errno(errno) - } else if n == 0 && errno == 0 && fd.proto != syscall.SOCK_DGRAM { + } else if n == 0 && err == nil && fd.proto != syscall.SOCK_DGRAM { err = io.EOF } break } - if oserr != nil { - err = &OpError{"read", fd.net, fd.raddr, oserr} + if err != nil && err != io.EOF { + err = &OpError{"read", fd.net, fd.raddr, err} } return } @@ -428,22 +436,22 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) { } else { fd.rdeadline = 0 } - var oserr error for { - var errno int - n, sa, errno = syscall.Recvfrom(fd.sysfd, p, 0) - if errno == syscall.EAGAIN && fd.rdeadline >= 0 { - pollserver.WaitRead(fd) - continue + n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0) + if err == syscall.EAGAIN { + if fd.rdeadline >= 0 { + pollserver.WaitRead(fd) + continue + } + err = errTimeout } - if errno != 0 { + if err != nil { n = 0 - oserr = os.Errno(errno) } break } - if oserr != nil { - err = &OpError{"read", fd.net, fd.laddr, oserr} + if err != nil { + err = &OpError{"read", fd.net, fd.laddr, err} } return } @@ -461,24 +469,22 @@ func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S } else { fd.rdeadline = 0 } - var oserr error for { - var errno int - n, oobn, flags, sa, errno = syscall.Recvmsg(fd.sysfd, p, oob, 0) - if errno == syscall.EAGAIN && fd.rdeadline >= 0 { - pollserver.WaitRead(fd) - continue - } - if errno != 0 { - oserr = os.Errno(errno) + n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0) + if err == syscall.EAGAIN { + if fd.rdeadline >= 0 { + pollserver.WaitRead(fd) + continue + } + err = errTimeout } - if n == 0 { - oserr = io.EOF + if err == nil && n == 0 { + err = io.EOF } break } - if oserr != nil { - err = &OpError{"read", fd.net, fd.laddr, oserr} + if err != nil && err != io.EOF { + err = &OpError{"read", fd.net, fd.laddr, err} return } return @@ -501,32 +507,34 @@ func (fd *netFD) Write(p []byte) (n int, err error) { fd.wdeadline = 0 } nn := 0 - var oserr error for { - n, errno := syscall.Write(fd.sysfile.Fd(), p[nn:]) + var n int + n, err = syscall.Write(fd.sysfile.Fd(), p[nn:]) if n > 0 { nn += n } if nn == len(p) { break } - if errno == syscall.EAGAIN && fd.wdeadline >= 0 { - pollserver.WaitWrite(fd) - continue + if err == syscall.EAGAIN { + if fd.wdeadline >= 0 { + pollserver.WaitWrite(fd) + continue + } + err = errTimeout } - if errno != 0 { + if err != nil { n = 0 - oserr = os.Errno(errno) break } if n == 0 { - oserr = io.ErrUnexpectedEOF + err = io.ErrUnexpectedEOF break } } - if oserr != nil { - err = &OpError{"write", fd.net, fd.raddr, oserr} + if err != nil { + err = &OpError{"write", fd.net, fd.raddr, err} } return nn, err } @@ -544,22 +552,21 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) { } else { fd.wdeadline = 0 } - var oserr error for { - errno := syscall.Sendto(fd.sysfd, p, 0, sa) - if errno == syscall.EAGAIN && fd.wdeadline >= 0 { - pollserver.WaitWrite(fd) - continue - } - if errno != 0 { - oserr = os.Errno(errno) + err = syscall.Sendto(fd.sysfd, p, 0, sa) + if err == syscall.EAGAIN { + if fd.wdeadline >= 0 { + pollserver.WaitWrite(fd) + continue + } + err = errTimeout } break } - if oserr == nil { + if err == nil { n = len(p) } else { - err = &OpError{"write", fd.net, fd.raddr, oserr} + err = &OpError{"write", fd.net, fd.raddr, err} } return } @@ -577,24 +584,22 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob } else { fd.wdeadline = 0 } - var oserr error for { - var errno int - errno = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0) - if errno == syscall.EAGAIN && fd.wdeadline >= 0 { - pollserver.WaitWrite(fd) - continue - } - if errno != 0 { - oserr = os.Errno(errno) + err = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0) + if err == syscall.EAGAIN { + if fd.wdeadline >= 0 { + pollserver.WaitWrite(fd) + continue + } + err = errTimeout } break } - if oserr == nil { + if err == nil { n = len(p) oobn = len(oob) } else { - err = &OpError{"write", fd.net, fd.raddr, oserr} + err = &OpError{"write", fd.net, fd.raddr, err} } return } @@ -615,25 +620,26 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err // See ../syscall/exec.go for description of ForkLock. // It is okay to hold the lock across syscall.Accept // because we have put fd.sysfd into non-blocking mode. - syscall.ForkLock.RLock() - var s, e int + var s int var rsa syscall.Sockaddr for { if fd.closing { - syscall.ForkLock.RUnlock() return nil, os.EINVAL } - s, rsa, e = syscall.Accept(fd.sysfd) - if e != syscall.EAGAIN || fd.rdeadline < 0 { - break - } - syscall.ForkLock.RUnlock() - pollserver.WaitRead(fd) syscall.ForkLock.RLock() - } - if e != 0 { - syscall.ForkLock.RUnlock() - return nil, &OpError{"accept", fd.net, fd.laddr, os.Errno(e)} + s, rsa, err = syscall.Accept(fd.sysfd) + if err != nil { + syscall.ForkLock.RUnlock() + if err == syscall.EAGAIN { + if fd.rdeadline >= 0 { + pollserver.WaitRead(fd) + continue + } + err = errTimeout + } + return nil, &OpError{"accept", fd.net, fd.laddr, err} + } + break } syscall.CloseOnExec(s) syscall.ForkLock.RUnlock() @@ -648,19 +654,19 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err } func (fd *netFD) dup() (f *os.File, err error) { - ns, e := syscall.Dup(fd.sysfd) - if e != 0 { - return nil, &OpError{"dup", fd.net, fd.laddr, os.Errno(e)} + ns, err := syscall.Dup(fd.sysfd) + if err != nil { + return nil, &OpError{"dup", fd.net, fd.laddr, err} } // We want blocking mode for the new fd, hence the double negative. - if e = syscall.SetNonblock(ns, false); e != 0 { - return nil, &OpError{"setnonblock", fd.net, fd.laddr, os.Errno(e)} + if err = syscall.SetNonblock(ns, false); err != nil { + return nil, &OpError{"setnonblock", fd.net, fd.laddr, err} } return os.NewFile(ns, fd.sysfile.Name()), nil } -func closesocket(s int) (errno int) { +func closesocket(s int) error { return syscall.Close(s) } diff --git a/libgo/go/net/fd_linux.go b/libgo/go/net/fd_linux.go index cce74cd..8e07833 100644 --- a/libgo/go/net/fd_linux.go +++ b/libgo/go/net/fd_linux.go @@ -35,12 +35,12 @@ type pollster struct { func newpollster() (p *pollster, err error) { p = new(pollster) - var e int + var e error // The arg to epoll_create is a hint to the kernel // about the number of FDs we will care about. // We don't know, and since 2.6.8 the kernel ignores it anyhow. - if p.epfd, e = syscall.EpollCreate(16); e != 0 { + if p.epfd, e = syscall.EpollCreate(16); e != nil { return nil, os.NewSyscallError("epoll_create", e) } p.events = make(map[int]uint32) @@ -68,7 +68,7 @@ func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) { } else { op = syscall.EPOLL_CTL_ADD } - if e := syscall.EpollCtl(p.epfd, op, fd, &p.ctlEvent); e != 0 { + if e := syscall.EpollCtl(p.epfd, op, fd, &p.ctlEvent); e != nil { return false, os.NewSyscallError("epoll_ctl", e) } p.events[fd] = p.ctlEvent.Events @@ -97,13 +97,13 @@ func (p *pollster) StopWaiting(fd int, bits uint) { if int32(events)&^syscall.EPOLLONESHOT != 0 { p.ctlEvent.Fd = int32(fd) p.ctlEvent.Events = events - if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &p.ctlEvent); e != 0 { - print("Epoll modify fd=", fd, ": ", os.Errno(e).Error(), "\n") + if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &p.ctlEvent); e != nil { + print("Epoll modify fd=", fd, ": ", e.Error(), "\n") } p.events[fd] = events } else { - if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_DEL, fd, nil); e != 0 { - print("Epoll delete fd=", fd, ": ", os.Errno(e).Error(), "\n") + if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_DEL, fd, nil); e != nil { + print("Epoll delete fd=", fd, ": ", e.Error(), "\n") } delete(p.events, fd) } @@ -141,7 +141,7 @@ func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err erro n, e := syscall.EpollWait(p.epfd, p.waitEventBuf[0:], msec) s.Lock() - if e != 0 { + if e != nil { if e == syscall.EAGAIN || e == syscall.EINTR { continue } diff --git a/libgo/go/net/fd_openbsd.go b/libgo/go/net/fd_openbsd.go index f61008a..e52ac35 100644 --- a/libgo/go/net/fd_openbsd.go +++ b/libgo/go/net/fd_openbsd.go @@ -23,9 +23,8 @@ type pollster struct { func newpollster() (p *pollster, err error) { p = new(pollster) - var e int - if p.kq, e = syscall.Kqueue(); e != 0 { - return nil, os.NewSyscallError("kqueue", e) + if p.kq, err = syscall.Kqueue(); err != nil { + return nil, os.NewSyscallError("kqueue", err) } p.events = p.eventbuf[0:0] return p, nil @@ -50,14 +49,14 @@ func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) { syscall.SetKevent(ev, fd, kmode, flags) n, e := syscall.Kevent(p.kq, p.kbuf[:], nil, nil) - if e != 0 { + if e != nil { return false, os.NewSyscallError("kevent", e) } if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode { return false, os.NewSyscallError("kqueue phase error", e) } if ev.Data != 0 { - return false, os.Errno(int(ev.Data)) + return false, syscall.Errno(int(ev.Data)) } return false, nil } @@ -91,7 +90,7 @@ func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err erro nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[:], t) s.Lock() - if e != 0 { + if e != nil { if e == syscall.EINTR { continue } diff --git a/libgo/go/net/fd_windows.go b/libgo/go/net/fd_windows.go index ce228e9..7a16023 100644 --- a/libgo/go/net/fd_windows.go +++ b/libgo/go/net/fd_windows.go @@ -26,11 +26,11 @@ func init() { var d syscall.WSAData e := syscall.WSAStartup(uint32(0x202), &d) if e != 0 { - initErr = os.NewSyscallError("WSAStartup", e) + initErr = os.NewSyscallError("WSAStartup", syscall.Errno(e)) } } -func closesocket(s syscall.Handle) (errno int) { +func closesocket(s syscall.Handle) (err error) { return syscall.Closesocket(s) } @@ -38,13 +38,13 @@ func closesocket(s syscall.Handle) (errno int) { type anOpIface interface { Op() *anOp Name() string - Submit() (errno int) + Submit() (err error) } // IO completion result parameters. type ioResult struct { qty uint32 - err int + err error } // anOp implements functionality common to all io operations. @@ -54,7 +54,7 @@ type anOp struct { o syscall.Overlapped resultc chan ioResult - errnoc chan int + errnoc chan error fd *netFD } @@ -71,7 +71,7 @@ func (o *anOp) Init(fd *netFD, mode int) { } o.resultc = fd.resultc[i] if fd.errnoc[i] == nil { - fd.errnoc[i] = make(chan int) + fd.errnoc[i] = make(chan error) } o.errnoc = fd.errnoc[i] } @@ -111,14 +111,14 @@ func (s *resultSrv) Run() { for { r.err = syscall.GetQueuedCompletionStatus(s.iocp, &(r.qty), &key, &o, syscall.INFINITE) switch { - case r.err == 0: + case r.err == nil: // Dequeued successfully completed io packet. - case r.err == syscall.WAIT_TIMEOUT && o == nil: + case r.err == syscall.Errno(syscall.WAIT_TIMEOUT) && o == nil: // Wait has timed out (should not happen now, but might be used in the future). panic("GetQueuedCompletionStatus timed out") case o == nil: // Failed to dequeue anything -> report the error. - panic("GetQueuedCompletionStatus failed " + syscall.Errstr(r.err)) + panic("GetQueuedCompletionStatus failed " + r.err.Error()) default: // Dequeued failed io packet. } @@ -153,7 +153,7 @@ func (s *ioSrv) ProcessRemoteIO() { // inline, or, if timeouts are employed, passes the request onto // a special goroutine and waits for completion or cancels request. func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err error) { - var e int + var e error o := oi.Op() if deadline_delta > 0 { // Send request to a special dedicated thread, @@ -164,12 +164,12 @@ func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err error) { e = oi.Submit() } switch e { - case 0: + case nil: // IO completed immediately, but we need to get our completion message anyway. case syscall.ERROR_IO_PENDING: // IO started, and we have to wait for its completion. default: - return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, os.Errno(e)} + return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, e} } // Wait for our request to complete. var r ioResult @@ -187,8 +187,8 @@ func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err error) { } else { r = <-o.resultc } - if r.err != 0 { - err = &OpError{oi.Name(), o.fd.net, o.fd.laddr, os.Errno(r.err)} + if r.err != nil { + err = &OpError{oi.Name(), o.fd.net, o.fd.laddr, r.err} } return int(r.qty), err } @@ -200,10 +200,10 @@ var onceStartServer sync.Once func startServer() { resultsrv = new(resultSrv) - var errno int - resultsrv.iocp, errno = syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 1) - if errno != 0 { - panic("CreateIoCompletionPort failed " + syscall.Errstr(errno)) + var err error + resultsrv.iocp, err = syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 1) + if err != nil { + panic("CreateIoCompletionPort: " + err.Error()) } go resultsrv.Run() @@ -228,7 +228,7 @@ type netFD struct { laddr Addr raddr Addr resultc [2]chan ioResult // read/write completion results - errnoc [2]chan int // read/write submit or cancel operation errors + errnoc [2]chan error // read/write submit or cancel operation errors // owned by client rdeadline_delta int64 @@ -256,8 +256,8 @@ func newFD(fd syscall.Handle, family, proto int, net string) (f *netFD, err erro } onceStartServer.Do(startServer) // Associate our socket with resultsrv.iocp. - if _, e := syscall.CreateIoCompletionPort(syscall.Handle(fd), resultsrv.iocp, 0, 0); e != 0 { - return nil, os.Errno(e) + if _, e := syscall.CreateIoCompletionPort(syscall.Handle(fd), resultsrv.iocp, 0, 0); e != nil { + return nil, e } return allocFD(fd, family, proto, net), nil } @@ -268,11 +268,7 @@ func (fd *netFD) setAddr(laddr, raddr Addr) { } func (fd *netFD) connect(ra syscall.Sockaddr) (err error) { - e := syscall.Connect(fd.sysfd, ra) - if e != 0 { - return os.Errno(e) - } - return nil + return syscall.Connect(fd.sysfd, ra) } // Add a reference to this fd. @@ -317,9 +313,9 @@ func (fd *netFD) shutdown(how int) error { if fd == nil || fd.sysfd == syscall.InvalidHandle { return os.EINVAL } - errno := syscall.Shutdown(fd.sysfd, how) - if errno != 0 { - return &OpError{"shutdown", fd.net, fd.laddr, os.Errno(errno)} + err := syscall.Shutdown(fd.sysfd, how) + if err != nil { + return &OpError{"shutdown", fd.net, fd.laddr, err} } return nil } @@ -338,7 +334,7 @@ type readOp struct { bufOp } -func (o *readOp) Submit() (errno int) { +func (o *readOp) Submit() (err error) { var d, f uint32 return syscall.WSARecv(syscall.Handle(o.fd.sysfd), &o.buf, 1, &d, &f, &o.o, nil) } @@ -375,7 +371,7 @@ type readFromOp struct { rsan int32 } -func (o *readFromOp) Submit() (errno int) { +func (o *readFromOp) Submit() (err error) { var d, f uint32 return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &d, &f, &o.rsa, &o.rsan, &o.o, nil) } @@ -415,7 +411,7 @@ type writeOp struct { bufOp } -func (o *writeOp) Submit() (errno int) { +func (o *writeOp) Submit() (err error) { var d uint32 return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &d, 0, &o.o, nil) } @@ -447,7 +443,7 @@ type writeToOp struct { sa syscall.Sockaddr } -func (o *writeToOp) Submit() (errno int) { +func (o *writeToOp) Submit() (err error) { var d uint32 return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &d, 0, o.sa, &o.o, nil) } @@ -484,7 +480,7 @@ type acceptOp struct { attrs [2]syscall.RawSockaddrAny // space for local and remote address only } -func (o *acceptOp) Submit() (errno int) { +func (o *acceptOp) Submit() (err error) { var d uint32 l := uint32(unsafe.Sizeof(o.attrs[0])) return syscall.AcceptEx(o.fd.sysfd, o.newsock, @@ -506,17 +502,17 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err // See ../syscall/exec.go for description of ForkLock. syscall.ForkLock.RLock() s, e := syscall.Socket(fd.family, fd.proto, 0) - if e != 0 { + if e != nil { syscall.ForkLock.RUnlock() - return nil, os.Errno(e) + return nil, e } syscall.CloseOnExec(s) syscall.ForkLock.RUnlock() // Associate our new socket with IOCP. onceStartServer.Do(startServer) - if _, e = syscall.CreateIoCompletionPort(s, resultsrv.iocp, 0, 0); e != 0 { - return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, os.Errno(e)} + if _, e = syscall.CreateIoCompletionPort(s, resultsrv.iocp, 0, 0); e != nil { + return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, e} } // Submit accept request. @@ -531,9 +527,9 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err // Inherit properties of the listening socket. e = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd))) - if e != 0 { + if e != nil { closesocket(s) - return nil, err + return nil, e } // Get local and peer addr out of AcceptEx buffer. diff --git a/libgo/go/net/file.go b/libgo/go/net/file.go index 0ad869d..bf8cd9d 100644 --- a/libgo/go/net/file.go +++ b/libgo/go/net/file.go @@ -13,12 +13,12 @@ import ( func newFileFD(f *os.File) (nfd *netFD, err error) { fd, errno := syscall.Dup(f.Fd()) - if errno != 0 { + if errno != nil { return nil, os.NewSyscallError("dup", errno) } proto, errno := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE) - if errno != 0 { + if errno != nil { return nil, os.NewSyscallError("getsockopt", errno) } diff --git a/libgo/go/net/hosts.go b/libgo/go/net/hosts.go index d75e9e0..ddfb074 100644 --- a/libgo/go/net/hosts.go +++ b/libgo/go/net/hosts.go @@ -7,8 +7,8 @@ package net import ( - "os" "sync" + "time" ) const cacheMaxAge = int64(300) // 5 minutes. @@ -26,7 +26,7 @@ var hosts struct { } func readHosts() { - now, _, _ := os.Time() + now := time.Seconds() hp := hostsPath if len(hosts.byName) == 0 || hosts.time+cacheMaxAge <= now || hosts.path != hp { hs := make(map[string][]string) @@ -51,7 +51,7 @@ func readHosts() { } } // Update the data cache. - hosts.time, _, _ = os.Time() + hosts.time = time.Seconds() hosts.path = hp hosts.byName = hs hosts.byAddr = is diff --git a/libgo/go/net/http/cgi/host_test.go b/libgo/go/net/http/cgi/host_test.go index 2bc913a..e6e85e8 100644 --- a/libgo/go/net/http/cgi/host_test.go +++ b/libgo/go/net/http/cgi/host_test.go @@ -363,14 +363,13 @@ func TestCopyError(t *testing.T) { } conn.Close() - if tries := 0; childRunning() { - for tries < 15 && childRunning() { - time.Sleep(50e6 * int64(tries)) - tries++ - } - if childRunning() { - t.Fatalf("post-conn.Close, expected child to be gone") - } + tries := 0 + for tries < 15 && childRunning() { + time.Sleep(50e6 * int64(tries)) + tries++ + } + if childRunning() { + t.Fatalf("post-conn.Close, expected child to be gone") } } diff --git a/libgo/go/net/http/chunked.go b/libgo/go/net/http/chunked.go index b012dd1..74c41aa 100644 --- a/libgo/go/net/http/chunked.go +++ b/libgo/go/net/http/chunked.go @@ -2,20 +2,137 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// The wire protocol for HTTP's "chunked" Transfer-Encoding. + +// This code is duplicated in httputil/chunked.go. +// Please make any changes in both files. + package http import ( "bufio" + "bytes" + "errors" "io" "strconv" ) +const maxLineLength = 4096 // assumed <= bufio.defaultBufSize + +var ErrLineTooLong = errors.New("header line too long") + +// newChunkedReader returns a new chunkedReader that translates the data read from r +// out of HTTP "chunked" format before returning it. +// The chunkedReader returns io.EOF when the final 0-length chunk is read. +// +// newChunkedReader is not needed by normal applications. The http package +// automatically decodes chunking when reading response bodies. +func newChunkedReader(r io.Reader) io.Reader { + br, ok := r.(*bufio.Reader) + if !ok { + br = bufio.NewReader(r) + } + return &chunkedReader{r: br} +} + +type chunkedReader struct { + r *bufio.Reader + n uint64 // unread bytes in chunk + err error +} + +func (cr *chunkedReader) beginChunk() { + // chunk-size CRLF + var line string + line, cr.err = readLine(cr.r) + if cr.err != nil { + return + } + cr.n, cr.err = strconv.Btoui64(line, 16) + if cr.err != nil { + return + } + if cr.n == 0 { + cr.err = io.EOF + } +} + +func (cr *chunkedReader) Read(b []uint8) (n int, err error) { + if cr.err != nil { + return 0, cr.err + } + if cr.n == 0 { + cr.beginChunk() + if cr.err != nil { + return 0, cr.err + } + } + if uint64(len(b)) > cr.n { + b = b[0:cr.n] + } + n, cr.err = cr.r.Read(b) + cr.n -= uint64(n) + if cr.n == 0 && cr.err == nil { + // end of chunk (CRLF) + b := make([]byte, 2) + if _, cr.err = io.ReadFull(cr.r, b); cr.err == nil { + if b[0] != '\r' || b[1] != '\n' { + cr.err = errors.New("malformed chunked encoding") + } + } + } + return n, cr.err +} + +// Read a line of bytes (up to \n) from b. +// Give up if the line exceeds maxLineLength. +// The returned bytes are a pointer into storage in +// the bufio, so they are only valid until the next bufio read. +func readLineBytes(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. + if err == io.EOF { + err = io.ErrUnexpectedEOF + } else if err == bufio.ErrBufferFull { + err = ErrLineTooLong + } + return nil, err + } + if len(p) >= maxLineLength { + return nil, ErrLineTooLong + } + + // Chop off trailing white space. + p = bytes.TrimRight(p, " \r\t\n") + + return 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 + } + return string(p), nil +} + +// newChunkedWriter returns a new chunkedWriter that translates writes into HTTP +// "chunked" format before writing them to w. Closing the returned chunkedWriter +// sends the final 0-length chunk that marks the end of the stream. +// +// newChunkedWriter is not needed by normal applications. The http +// package adds chunking automatically if handlers don't set a +// Content-Length header. Using newChunkedWriter inside a handler +// would result in double chunking or chunking with a Content-Length +// length, both of which are wrong. func newChunkedWriter(w io.Writer) io.WriteCloser { return &chunkedWriter{w} } -// Writing to ChunkedWriter translates to writing in HTTP chunked Transfer -// Encoding wire format to the underlying Wire writer. +// Writing to chunkedWriter translates to writing in HTTP chunked Transfer +// Encoding wire format to the underlying Wire chunkedWriter. type chunkedWriter struct { Wire io.Writer } @@ -51,7 +168,3 @@ func (cw *chunkedWriter) Close() error { _, err := io.WriteString(cw.Wire, "0\r\n") return err } - -func newChunkedReader(r *bufio.Reader) io.Reader { - return &chunkedReader{r: r} -} diff --git a/libgo/go/net/http/chunked_test.go b/libgo/go/net/http/chunked_test.go new file mode 100644 index 0000000..b77ee2f --- /dev/null +++ b/libgo/go/net/http/chunked_test.go @@ -0,0 +1,39 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code is duplicated in httputil/chunked_test.go. +// Please make any changes in both files. + +package http + +import ( + "bytes" + "io/ioutil" + "testing" +) + +func TestChunk(t *testing.T) { + var b bytes.Buffer + + w := newChunkedWriter(&b) + const chunk1 = "hello, " + const chunk2 = "world! 0123456789abcdef" + w.Write([]byte(chunk1)) + w.Write([]byte(chunk2)) + w.Close() + + if g, e := b.String(), "7\r\nhello, \r\n17\r\nworld! 0123456789abcdef\r\n0\r\n"; g != e { + t.Fatalf("chunk writer wrote %q; want %q", g, e) + } + + r := newChunkedReader(&b) + data, err := ioutil.ReadAll(r) + if err != nil { + t.Logf(`data: "%s"`, data) + t.Fatalf("ReadAll from reader: %v", err) + } + if g, e := string(data), chunk1+chunk2; g != e { + t.Errorf("chunk reader read %q; want %q", g, e) + } +} diff --git a/libgo/go/net/http/client_test.go b/libgo/go/net/http/client_test.go index d224380..57a9dd9 100644 --- a/libgo/go/net/http/client_test.go +++ b/libgo/go/net/http/client_test.go @@ -26,6 +26,31 @@ var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) { fmt.Fprintf(w, "User-agent: go\nDisallow: /something/") }) +// pedanticReadAll works like ioutil.ReadAll but additionally +// verifies that r obeys the documented io.Reader contract. +func pedanticReadAll(r io.Reader) (b []byte, err error) { + var bufa [64]byte + buf := bufa[:] + for { + n, err := r.Read(buf) + if n == 0 && err == nil { + return nil, fmt.Errorf("Read: n=0 with err=nil") + } + b = append(b, buf[:n]...) + if err == io.EOF { + n, err := r.Read(buf) + if n != 0 || err != io.EOF { + return nil, fmt.Errorf("Read: n=%d err=%#v after EOF", n, err) + } + return b, nil + } + if err != nil { + return b, err + } + } + panic("unreachable") +} + func TestClient(t *testing.T) { ts := httptest.NewServer(robotsTxtHandler) defer ts.Close() @@ -33,7 +58,7 @@ func TestClient(t *testing.T) { r, err := Get(ts.URL) var b []byte if err == nil { - b, err = ioutil.ReadAll(r.Body) + b, err = pedanticReadAll(r.Body) r.Body.Close() } if err != nil { diff --git a/libgo/go/net/http/fcgi/child.go b/libgo/go/net/http/fcgi/child.go index 7b56395..529440c 100644 --- a/libgo/go/net/http/fcgi/child.go +++ b/libgo/go/net/http/fcgi/child.go @@ -7,6 +7,7 @@ package fcgi // This file implements FastCGI from the perspective of a child process. import ( + "errors" "fmt" "io" "net" @@ -123,89 +124,101 @@ func (r *response) Close() error { } type child struct { - conn *conn - handler http.Handler + conn *conn + handler http.Handler + requests map[uint16]*request // keyed by request ID } -func newChild(rwc net.Conn, handler http.Handler) *child { - return &child{newConn(rwc), handler} +func newChild(rwc io.ReadWriteCloser, handler http.Handler) *child { + return &child{ + conn: newConn(rwc), + handler: handler, + requests: make(map[uint16]*request), + } } func (c *child) serve() { - requests := map[uint16]*request{} defer c.conn.Close() var rec record - var br beginRequest for { if err := rec.read(c.conn.rwc); err != nil { return } - - req, ok := requests[rec.h.Id] - if !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues { - // The spec says to ignore unknown request IDs. - continue - } - if ok && rec.h.Type == typeBeginRequest { - // The server is trying to begin a request with the same ID - // as an in-progress request. This is an error. + if err := c.handleRecord(&rec); err != nil { return } + } +} - switch rec.h.Type { - case typeBeginRequest: - if err := br.read(rec.content()); err != nil { - return - } - if br.role != roleResponder { - c.conn.writeEndRequest(rec.h.Id, 0, statusUnknownRole) - break - } - requests[rec.h.Id] = newRequest(rec.h.Id, br.flags) - case typeParams: - // NOTE(eds): Technically a key-value pair can straddle the boundary - // between two packets. We buffer until we've received all parameters. - if len(rec.content()) > 0 { - req.rawParams = append(req.rawParams, rec.content()...) - break - } - req.parseParams() - case typeStdin: - content := rec.content() - if req.pw == nil { - var body io.ReadCloser - if len(content) > 0 { - // body could be an io.LimitReader, but it shouldn't matter - // as long as both sides are behaving. - body, req.pw = io.Pipe() - } - go c.serveRequest(req, body) - } +var errCloseConn = errors.New("fcgi: connection should be closed") + +func (c *child) handleRecord(rec *record) error { + req, ok := c.requests[rec.h.Id] + if !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues { + // The spec says to ignore unknown request IDs. + return nil + } + if ok && rec.h.Type == typeBeginRequest { + // The server is trying to begin a request with the same ID + // as an in-progress request. This is an error. + return errors.New("fcgi: received ID that is already in-flight") + } + + switch rec.h.Type { + case typeBeginRequest: + var br beginRequest + if err := br.read(rec.content()); err != nil { + return err + } + if br.role != roleResponder { + c.conn.writeEndRequest(rec.h.Id, 0, statusUnknownRole) + return nil + } + c.requests[rec.h.Id] = newRequest(rec.h.Id, br.flags) + case typeParams: + // NOTE(eds): Technically a key-value pair can straddle the boundary + // between two packets. We buffer until we've received all parameters. + if len(rec.content()) > 0 { + req.rawParams = append(req.rawParams, rec.content()...) + return nil + } + req.parseParams() + case typeStdin: + content := rec.content() + if req.pw == nil { + var body io.ReadCloser if len(content) > 0 { - // TODO(eds): This blocks until the handler reads from the pipe. - // If the handler takes a long time, it might be a problem. - req.pw.Write(content) - } else if req.pw != nil { - req.pw.Close() - } - case typeGetValues: - values := map[string]string{"FCGI_MPXS_CONNS": "1"} - c.conn.writePairs(0, typeGetValuesResult, values) - case typeData: - // If the filter role is implemented, read the data stream here. - case typeAbortRequest: - delete(requests, rec.h.Id) - c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete) - if !req.keepConn { - // connection will close upon return - return + // body could be an io.LimitReader, but it shouldn't matter + // as long as both sides are behaving. + body, req.pw = io.Pipe() } - default: - b := make([]byte, 8) - b[0] = rec.h.Type - c.conn.writeRecord(typeUnknownType, 0, b) + go c.serveRequest(req, body) + } + if len(content) > 0 { + // TODO(eds): This blocks until the handler reads from the pipe. + // If the handler takes a long time, it might be a problem. + req.pw.Write(content) + } else if req.pw != nil { + req.pw.Close() + } + case typeGetValues: + values := map[string]string{"FCGI_MPXS_CONNS": "1"} + c.conn.writePairs(typeGetValuesResult, 0, values) + case typeData: + // If the filter role is implemented, read the data stream here. + case typeAbortRequest: + delete(c.requests, rec.h.Id) + c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete) + if !req.keepConn { + // connection will close upon return + return errCloseConn } + default: + b := make([]byte, 8) + b[0] = byte(rec.h.Type) + c.conn.writeRecord(typeUnknownType, 0, b) } + return nil } func (c *child) serveRequest(req *request, body io.ReadCloser) { diff --git a/libgo/go/net/http/fcgi/fcgi.go b/libgo/go/net/http/fcgi/fcgi.go index 70cf781..d35aa84 100644 --- a/libgo/go/net/http/fcgi/fcgi.go +++ b/libgo/go/net/http/fcgi/fcgi.go @@ -19,19 +19,22 @@ import ( "sync" ) +// recType is a record type, as defined by +// http://www.fastcgi.com/devkit/doc/fcgi-spec.html#S8 +type recType uint8 + const ( - // Packet Types - typeBeginRequest = iota + 1 - typeAbortRequest - typeEndRequest - typeParams - typeStdin - typeStdout - typeStderr - typeData - typeGetValues - typeGetValuesResult - typeUnknownType + typeBeginRequest recType = 1 + typeAbortRequest recType = 2 + typeEndRequest recType = 3 + typeParams recType = 4 + typeStdin recType = 5 + typeStdout recType = 6 + typeStderr recType = 7 + typeData recType = 8 + typeGetValues recType = 9 + typeGetValuesResult recType = 10 + typeUnknownType recType = 11 ) // keep the connection between web-server and responder open after request @@ -59,7 +62,7 @@ const headerLen = 8 type header struct { Version uint8 - Type uint8 + Type recType Id uint16 ContentLength uint16 PaddingLength uint8 @@ -85,7 +88,7 @@ func (br *beginRequest) read(content []byte) error { // not synchronized because we don't care what the contents are var pad [maxPad]byte -func (h *header) init(recType uint8, reqId uint16, contentLength int) { +func (h *header) init(recType recType, reqId uint16, contentLength int) { h.Version = 1 h.Type = recType h.Id = reqId @@ -137,7 +140,7 @@ func (r *record) content() []byte { } // writeRecord writes and sends a single record. -func (c *conn) writeRecord(recType uint8, reqId uint16, b []byte) error { +func (c *conn) writeRecord(recType recType, reqId uint16, b []byte) error { c.mutex.Lock() defer c.mutex.Unlock() c.buf.Reset() @@ -167,12 +170,12 @@ func (c *conn) writeEndRequest(reqId uint16, appStatus int, protocolStatus uint8 return c.writeRecord(typeEndRequest, reqId, b) } -func (c *conn) writePairs(recType uint8, reqId uint16, pairs map[string]string) error { +func (c *conn) writePairs(recType recType, reqId uint16, pairs map[string]string) error { w := newWriter(c, recType, reqId) b := make([]byte, 8) for k, v := range pairs { n := encodeSize(b, uint32(len(k))) - n += encodeSize(b[n:], uint32(len(k))) + n += encodeSize(b[n:], uint32(len(v))) if _, err := w.Write(b[:n]); err != nil { return err } @@ -235,7 +238,7 @@ func (w *bufWriter) Close() error { return w.closer.Close() } -func newWriter(c *conn, recType uint8, reqId uint16) *bufWriter { +func newWriter(c *conn, recType recType, reqId uint16) *bufWriter { s := &streamWriter{c: c, recType: recType, reqId: reqId} w, _ := bufio.NewWriterSize(s, maxWrite) return &bufWriter{s, w} @@ -245,7 +248,7 @@ func newWriter(c *conn, recType uint8, reqId uint16) *bufWriter { // It only writes maxWrite bytes at a time. type streamWriter struct { c *conn - recType uint8 + recType recType reqId uint16 } diff --git a/libgo/go/net/http/fcgi/fcgi_test.go b/libgo/go/net/http/fcgi/fcgi_test.go index e42f8ef..6c7e1a9 100644 --- a/libgo/go/net/http/fcgi/fcgi_test.go +++ b/libgo/go/net/http/fcgi/fcgi_test.go @@ -6,6 +6,7 @@ package fcgi import ( "bytes" + "errors" "io" "testing" ) @@ -40,25 +41,25 @@ func TestSize(t *testing.T) { var streamTests = []struct { desc string - recType uint8 + recType recType reqId uint16 content []byte raw []byte }{ {"single record", typeStdout, 1, nil, - []byte{1, typeStdout, 0, 1, 0, 0, 0, 0}, + []byte{1, byte(typeStdout), 0, 1, 0, 0, 0, 0}, }, // this data will have to be split into two records {"two records", typeStdin, 300, make([]byte, 66000), bytes.Join([][]byte{ // header for the first record - {1, typeStdin, 0x01, 0x2C, 0xFF, 0xFF, 1, 0}, + {1, byte(typeStdin), 0x01, 0x2C, 0xFF, 0xFF, 1, 0}, make([]byte, 65536), // header for the second - {1, typeStdin, 0x01, 0x2C, 0x01, 0xD1, 7, 0}, + {1, byte(typeStdin), 0x01, 0x2C, 0x01, 0xD1, 7, 0}, make([]byte, 472), // header for the empty record - {1, typeStdin, 0x01, 0x2C, 0, 0, 0, 0}, + {1, byte(typeStdin), 0x01, 0x2C, 0, 0, 0, 0}, }, nil), }, @@ -111,3 +112,39 @@ outer: } } } + +type writeOnlyConn struct { + buf []byte +} + +func (c *writeOnlyConn) Write(p []byte) (int, error) { + c.buf = append(c.buf, p...) + return len(p), nil +} + +func (c *writeOnlyConn) Read(p []byte) (int, error) { + return 0, errors.New("conn is write-only") +} + +func (c *writeOnlyConn) Close() error { + return nil +} + +func TestGetValues(t *testing.T) { + var rec record + rec.h.Type = typeGetValues + + wc := new(writeOnlyConn) + c := newChild(wc, nil) + err := c.handleRecord(&rec) + if err != nil { + t.Fatalf("handleRecord: %v", err) + } + + const want = "\x01\n\x00\x00\x00\x12\x06\x00" + + "\x0f\x01FCGI_MPXS_CONNS1" + + "\x00\x00\x00\x00\x00\x00\x01\n\x00\x00\x00\x00\x00\x00" + if got := string(wc.buf); got != want { + t.Errorf(" got: %q\nwant: %q\n", got, want) + } +} diff --git a/libgo/go/net/http/fs.go b/libgo/go/net/http/fs.go index 5f91ff5..5aadac1 100644 --- a/libgo/go/net/http/fs.go +++ b/libgo/go/net/http/fs.go @@ -22,13 +22,19 @@ import ( // A Dir implements http.FileSystem using the native file // system restricted to a specific directory tree. +// +// An empty Dir is treated as ".". type Dir string func (d Dir) Open(name string) (File, error) { if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 { return nil, errors.New("http: invalid character in file path") } - f, err := os.Open(filepath.Join(string(d), filepath.FromSlash(path.Clean("/"+name)))) + dir := string(d) + if dir == "" { + dir = "." + } + f, err := os.Open(filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name)))) if err != nil { return nil, err } diff --git a/libgo/go/net/http/fs_test.go b/libgo/go/net/http/fs_test.go index e1a784c..6697189 100644 --- a/libgo/go/net/http/fs_test.go +++ b/libgo/go/net/http/fs_test.go @@ -208,6 +208,20 @@ func TestDirJoin(t *testing.T) { test(Dir("/etc/hosts"), "../") } +func TestEmptyDirOpenCWD(t *testing.T) { + test := func(d Dir) { + name := "fs_test.go" + f, err := d.Open(name) + if err != nil { + t.Fatalf("open of %s: %v", name, err) + } + defer f.Close() + } + test(Dir("")) + test(Dir(".")) + test(Dir("./")) +} + func TestServeFileContentType(t *testing.T) { const ctype = "icecream/chocolate" override := false @@ -247,6 +261,20 @@ func TestServeFileMimeType(t *testing.T) { } } +func TestServeFileFromCWD(t *testing.T) { + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + ServeFile(w, r, "fs_test.go") + })) + defer ts.Close() + r, err := Get(ts.URL) + if err != nil { + t.Fatal(err) + } + if r.StatusCode != 200 { + t.Fatalf("expected 200 OK, got %s", r.Status) + } +} + func TestServeFileWithContentEncoding(t *testing.T) { ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { w.Header().Set("Content-Encoding", "foo") diff --git a/libgo/go/net/http/httputil/chunked.go b/libgo/go/net/http/httputil/chunked.go index 34e47c7..69bcc0e 100644 --- a/libgo/go/net/http/httputil/chunked.go +++ b/libgo/go/net/http/httputil/chunked.go @@ -2,18 +2,126 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// The wire protocol for HTTP's "chunked" Transfer-Encoding. + +// This code is a duplicate of ../chunked.go with these edits: +// s/newChunked/NewChunked/g +// s/package http/package httputil/ +// Please make any changes in both files. + package httputil import ( "bufio" + "bytes" + "errors" "io" - "net/http" "strconv" - "strings" ) -// NewChunkedWriter returns a new writer that translates writes into HTTP -// "chunked" format before writing them to w. Closing the returned writer +const maxLineLength = 4096 // assumed <= bufio.defaultBufSize + +var ErrLineTooLong = errors.New("header line too long") + +// NewChunkedReader returns a new chunkedReader that translates the data read from r +// out of HTTP "chunked" format before returning it. +// The chunkedReader returns io.EOF when the final 0-length chunk is read. +// +// NewChunkedReader is not needed by normal applications. The http package +// automatically decodes chunking when reading response bodies. +func NewChunkedReader(r io.Reader) io.Reader { + br, ok := r.(*bufio.Reader) + if !ok { + br = bufio.NewReader(r) + } + return &chunkedReader{r: br} +} + +type chunkedReader struct { + r *bufio.Reader + n uint64 // unread bytes in chunk + err error +} + +func (cr *chunkedReader) beginChunk() { + // chunk-size CRLF + var line string + line, cr.err = readLine(cr.r) + if cr.err != nil { + return + } + cr.n, cr.err = strconv.Btoui64(line, 16) + if cr.err != nil { + return + } + if cr.n == 0 { + cr.err = io.EOF + } +} + +func (cr *chunkedReader) Read(b []uint8) (n int, err error) { + if cr.err != nil { + return 0, cr.err + } + if cr.n == 0 { + cr.beginChunk() + if cr.err != nil { + return 0, cr.err + } + } + if uint64(len(b)) > cr.n { + b = b[0:cr.n] + } + n, cr.err = cr.r.Read(b) + cr.n -= uint64(n) + if cr.n == 0 && cr.err == nil { + // end of chunk (CRLF) + b := make([]byte, 2) + if _, cr.err = io.ReadFull(cr.r, b); cr.err == nil { + if b[0] != '\r' || b[1] != '\n' { + cr.err = errors.New("malformed chunked encoding") + } + } + } + return n, cr.err +} + +// Read a line of bytes (up to \n) from b. +// Give up if the line exceeds maxLineLength. +// The returned bytes are a pointer into storage in +// the bufio, so they are only valid until the next bufio read. +func readLineBytes(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. + if err == io.EOF { + err = io.ErrUnexpectedEOF + } else if err == bufio.ErrBufferFull { + err = ErrLineTooLong + } + return nil, err + } + if len(p) >= maxLineLength { + return nil, ErrLineTooLong + } + + // Chop off trailing white space. + p = bytes.TrimRight(p, " \r\t\n") + + return 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 + } + return string(p), nil +} + +// NewChunkedWriter returns a new chunkedWriter that translates writes into HTTP +// "chunked" format before writing them to w. Closing the returned chunkedWriter // sends the final 0-length chunk that marks the end of the stream. // // NewChunkedWriter is not needed by normal applications. The http @@ -25,8 +133,8 @@ func NewChunkedWriter(w io.Writer) io.WriteCloser { return &chunkedWriter{w} } -// Writing to ChunkedWriter translates to writing in HTTP chunked Transfer -// Encoding wire format to the underlying Wire writer. +// Writing to chunkedWriter translates to writing in HTTP chunked Transfer +// Encoding wire format to the underlying Wire chunkedWriter. type chunkedWriter struct { Wire io.Writer } @@ -62,23 +170,3 @@ func (cw *chunkedWriter) Close() error { _, err := io.WriteString(cw.Wire, "0\r\n") return err } - -// NewChunkedReader returns a new reader that translates the data read from r -// out of HTTP "chunked" format before returning it. -// The reader returns io.EOF when the final 0-length chunk is read. -// -// NewChunkedReader is not needed by normal applications. The http package -// automatically decodes chunking when reading response bodies. -func NewChunkedReader(r io.Reader) io.Reader { - // This is a bit of a hack so we don't have to copy chunkedReader into - // httputil. It's a bit more complex than chunkedWriter, which is copied - // above. - req, err := http.ReadRequest(bufio.NewReader(io.MultiReader( - strings.NewReader("POST / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"), - r, - strings.NewReader("\r\n")))) - if err != nil { - panic("bad fake request: " + err.Error()) - } - return req.Body -} diff --git a/libgo/go/net/http/httputil/chunked_test.go b/libgo/go/net/http/httputil/chunked_test.go index 258d39b9..155a32b 100644 --- a/libgo/go/net/http/httputil/chunked_test.go +++ b/libgo/go/net/http/httputil/chunked_test.go @@ -2,6 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// This code is a duplicate of ../chunked_test.go with these edits: +// s/newChunked/NewChunked/g +// s/package http/package httputil/ +// Please make any changes in both files. + package httputil import ( @@ -27,7 +32,8 @@ func TestChunk(t *testing.T) { r := NewChunkedReader(&b) data, err := ioutil.ReadAll(r) if err != nil { - t.Fatalf("ReadAll from NewChunkedReader: %v", err) + t.Logf(`data: "%s"`, data) + t.Fatalf("ReadAll from reader: %v", err) } if g, e := string(data), chunk1+chunk2; g != e { t.Errorf("chunk reader read %q; want %q", g, e) diff --git a/libgo/go/net/http/httputil/persist.go b/libgo/go/net/http/httputil/persist.go index d7b67011..1266bd3 100644 --- a/libgo/go/net/http/httputil/persist.go +++ b/libgo/go/net/http/httputil/persist.go @@ -22,6 +22,10 @@ var ( ErrPipeline = &http.ProtocolError{"pipeline error"} ) +// This is an API usage error - the local side is closed. +// ErrPersistEOF (above) reports that the remote side is closed. +var errClosed = errors.New("i/o operation on closed connection") + // A ServerConn reads requests and sends responses over an underlying // connection, until the HTTP keepalive logic commands an end. ServerConn // also allows hijacking the underlying connection by calling Hijack @@ -108,7 +112,7 @@ func (sc *ServerConn) Read() (req *http.Request, err error) { } if sc.r == nil { // connection closed by user in the meantime defer sc.lk.Unlock() - return nil, os.EBADF + return nil, errClosed } r := sc.r lastbody := sc.lastbody @@ -313,7 +317,7 @@ func (cc *ClientConn) Write(req *http.Request) (err error) { } if cc.c == nil { // connection closed by user in the meantime defer cc.lk.Unlock() - return os.EBADF + return errClosed } c := cc.c if req.Close { @@ -369,7 +373,7 @@ func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error) { } if cc.r == nil { // connection closed by user in the meantime defer cc.lk.Unlock() - return nil, os.EBADF + return nil, errClosed } r := cc.r lastbody := cc.lastbody diff --git a/libgo/go/net/http/readrequest_test.go b/libgo/go/net/http/readrequest_test.go index 2219d43..c64fff6 100644 --- a/libgo/go/net/http/readrequest_test.go +++ b/libgo/go/net/http/readrequest_test.go @@ -70,7 +70,6 @@ var reqTests = []reqTest{ Close: false, ContentLength: 7, Host: "www.techcrunch.com", - Form: url.Values{}, }, "abcdef\n", @@ -94,10 +93,10 @@ var reqTests = []reqTest{ Proto: "HTTP/1.1", ProtoMajor: 1, ProtoMinor: 1, + Header: Header{}, Close: false, ContentLength: 0, Host: "foo.com", - Form: url.Values{}, }, noBody, @@ -131,7 +130,6 @@ var reqTests = []reqTest{ Close: false, ContentLength: 0, Host: "test", - Form: url.Values{}, }, noBody, @@ -180,9 +178,9 @@ var reqTests = []reqTest{ Proto: "HTTP/1.1", ProtoMajor: 1, ProtoMinor: 1, + Header: Header{}, ContentLength: -1, Host: "foo.com", - Form: url.Values{}, }, "foobar", diff --git a/libgo/go/net/http/request.go b/libgo/go/net/http/request.go index 4410ca1..6617849 100644 --- a/libgo/go/net/http/request.go +++ b/libgo/go/net/http/request.go @@ -19,12 +19,10 @@ import ( "mime/multipart" "net/textproto" "net/url" - "strconv" "strings" ) const ( - maxLineLength = 4096 // assumed <= bufio.defaultBufSize maxValueLength = 4096 maxHeaderLines = 1024 chunkSize = 4 << 10 // 4 KB chunks @@ -43,7 +41,6 @@ type ProtocolError struct { func (err *ProtocolError) Error() string { return err.ErrorString } var ( - ErrLineTooLong = &ProtocolError{"header line too long"} ErrHeaderTooLong = &ProtocolError{"header too long"} ErrShortBody = &ProtocolError{"entity body too short"} ErrNotSupported = &ProtocolError{"feature not supported"} @@ -375,44 +372,6 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err return nil } -// Read a line of bytes (up to \n) from b. -// Give up if the line exceeds maxLineLength. -// The returned bytes are a pointer into storage in -// the bufio, so they are only valid until the next bufio read. -func readLineBytes(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. - if err == io.EOF { - err = io.ErrUnexpectedEOF - } else if err == bufio.ErrBufferFull { - err = ErrLineTooLong - } - return nil, err - } - if len(p) >= maxLineLength { - return nil, ErrLineTooLong - } - - // Chop off trailing white space. - var i int - for i = len(p); i > 0; i-- { - if c := p[i-1]; c != ' ' && c != '\r' && c != '\t' && c != '\n' { - break - } - } - return p[0:i], 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 - } - return string(p), nil -} - // Convert decimal at s[i:len(s)] to integer, // returning value, string position where the digits stopped, // and whether there was a valid number (digits, not too big). @@ -448,55 +407,6 @@ func ParseHTTPVersion(vers string) (major, minor int, ok bool) { return major, minor, true } -type chunkedReader struct { - r *bufio.Reader - n uint64 // unread bytes in chunk - err error -} - -func (cr *chunkedReader) beginChunk() { - // chunk-size CRLF - var line string - line, cr.err = readLine(cr.r) - if cr.err != nil { - return - } - cr.n, cr.err = strconv.Btoui64(line, 16) - if cr.err != nil { - return - } - if cr.n == 0 { - cr.err = io.EOF - } -} - -func (cr *chunkedReader) Read(b []uint8) (n int, err error) { - if cr.err != nil { - return 0, cr.err - } - if cr.n == 0 { - cr.beginChunk() - if cr.err != nil { - return 0, cr.err - } - } - if uint64(len(b)) > cr.n { - b = b[0:cr.n] - } - n, cr.err = cr.r.Read(b) - cr.n -= uint64(n) - if cr.n == 0 && cr.err == nil { - // end of chunk (CRLF) - b := make([]byte, 2) - if _, cr.err = io.ReadFull(cr.r, b); cr.err == nil { - if b[0] != '\r' || b[1] != '\n' { - cr.err = errors.New("malformed chunked encoding") - } - } - } - return n, cr.err -} - // NewRequest returns a new Request given a method, URL, and optional body. func NewRequest(method, urlStr string, body io.Reader) (*Request, error) { u, err := url.Parse(urlStr) diff --git a/libgo/go/net/http/response_test.go b/libgo/go/net/http/response_test.go index be717aa..e5d0169 100644 --- a/libgo/go/net/http/response_test.go +++ b/libgo/go/net/http/response_test.go @@ -65,6 +65,7 @@ var respTests = []respTest{ Proto: "HTTP/1.1", ProtoMajor: 1, ProtoMinor: 1, + Header: Header{}, Request: dummyReq("GET"), Close: true, ContentLength: -1, @@ -85,6 +86,7 @@ var respTests = []respTest{ Proto: "HTTP/1.1", ProtoMajor: 1, ProtoMinor: 1, + Header: Header{}, Request: dummyReq("GET"), Close: false, ContentLength: 0, @@ -315,7 +317,7 @@ func TestReadResponseCloseInMiddle(t *testing.T) { } var wr io.Writer = &buf if test.chunked { - wr = &chunkedWriter{wr} + wr = newChunkedWriter(wr) } if test.compressed { buf.WriteString("Content-Encoding: gzip\r\n") diff --git a/libgo/go/net/http/serve_test.go b/libgo/go/net/http/serve_test.go index e278396..97a0b13 100644 --- a/libgo/go/net/http/serve_test.go +++ b/libgo/go/net/http/serve_test.go @@ -1077,6 +1077,31 @@ func TestClientWriteShutdown(t *testing.T) { } } +// Tests that chunked server responses that write 1 byte at a time are +// buffered before chunk headers are added, not after chunk headers. +func TestServerBufferedChunking(t *testing.T) { + if true { + t.Logf("Skipping known broken test; see Issue 2357") + return + } + conn := new(testConn) + conn.readBuf.Write([]byte("GET / HTTP/1.1\r\n\r\n")) + done := make(chan bool) + ls := &oneConnListener{conn} + go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) { + defer close(done) + rw.Header().Set("Content-Type", "text/plain") // prevent sniffing, which buffers + rw.Write([]byte{'x'}) + rw.Write([]byte{'y'}) + rw.Write([]byte{'z'}) + })) + <-done + if !bytes.HasSuffix(conn.writeBuf.Bytes(), []byte("\r\n\r\n3\r\nxyz\r\n0\r\n\r\n")) { + t.Errorf("response didn't end with a single 3 byte 'xyz' chunk; got:\n%q", + conn.writeBuf.Bytes()) + } +} + // goTimeout runs f, failing t if f takes more than ns to complete. func goTimeout(t *testing.T, ns int64, f func()) { ch := make(chan bool, 2) @@ -1120,7 +1145,7 @@ func TestAcceptMaxFds(t *testing.T) { ln := &errorListener{[]error{ &net.OpError{ Op: "accept", - Err: os.Errno(syscall.EMFILE), + Err: syscall.EMFILE, }}} err := Serve(ln, HandlerFunc(HandlerFunc(func(ResponseWriter, *Request) {}))) if err != io.EOF { diff --git a/libgo/go/net/http/server.go b/libgo/go/net/http/server.go index 8c48894..7221d25 100644 --- a/libgo/go/net/http/server.go +++ b/libgo/go/net/http/server.go @@ -149,11 +149,13 @@ type writerOnly struct { } func (w *response) ReadFrom(src io.Reader) (n int64, err error) { - // Flush before checking w.chunking, as Flush will call - // WriteHeader if it hasn't been called yet, and WriteHeader - // is what sets w.chunking. - w.Flush() + // Call WriteHeader before checking w.chunking if it hasn't + // been called yet, since WriteHeader is what sets w.chunking. + if !w.wroteHeader { + w.WriteHeader(StatusOK) + } if !w.chunking && w.bodyAllowed() && !w.needSniff { + w.Flush() if rf, ok := w.conn.rwc.(io.ReaderFrom); ok { n, err = rf.ReadFrom(src) w.written += n diff --git a/libgo/go/net/http/sniff_test.go b/libgo/go/net/http/sniff_test.go index a414e64..86744ee 100644 --- a/libgo/go/net/http/sniff_test.go +++ b/libgo/go/net/http/sniff_test.go @@ -6,6 +6,7 @@ package http_test import ( "bytes" + "io" "io/ioutil" "log" . "net/http" @@ -79,3 +80,35 @@ func TestServerContentType(t *testing.T) { resp.Body.Close() } } + +func TestContentTypeWithCopy(t *testing.T) { + const ( + input = "\n<html>\n\t<head>\n" + expected = "text/html; charset=utf-8" + ) + + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + // Use io.Copy from a bytes.Buffer to trigger ReadFrom. + buf := bytes.NewBuffer([]byte(input)) + n, err := io.Copy(w, buf) + if int(n) != len(input) || err != nil { + t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input)) + } + })) + defer ts.Close() + + resp, err := Get(ts.URL) + if err != nil { + t.Fatalf("Get: %v", err) + } + if ct := resp.Header.Get("Content-Type"); ct != expected { + t.Errorf("Content-Type = %q, want %q", ct, expected) + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Errorf("reading body: %v", err) + } else if !bytes.Equal(data, []byte(input)) { + t.Errorf("data is %q, want %q", data, input) + } + resp.Body.Close() +} diff --git a/libgo/go/net/http/transfer.go b/libgo/go/net/http/transfer.go index 2670d77..d25c8fc 100644 --- a/libgo/go/net/http/transfer.go +++ b/libgo/go/net/http/transfer.go @@ -537,7 +537,9 @@ func (b *body) Read(p []byte) (n int, err error) { // Read the final trailer once we hit EOF. if err == io.EOF && b.hdr != nil { - err = b.readTrailer() + if e := b.readTrailer(); e != nil { + err = e + } b.hdr = nil } return n, err diff --git a/libgo/go/net/http/transport.go b/libgo/go/net/http/transport.go index da5244b..e622e41 100644 --- a/libgo/go/net/http/transport.go +++ b/libgo/go/net/http/transport.go @@ -504,7 +504,7 @@ func (pc *persistConn) expectingResponse() bool { var remoteSideClosedFunc func(error) bool // or nil to use default func remoteSideClosed(err error) bool { - if err == io.EOF || err == os.EINVAL { + if err == io.EOF { return true } if remoteSideClosedFunc != nil { diff --git a/libgo/go/net/http/transport_windows.go b/libgo/go/net/http/transport_windows.go index 2a20d22..c9ef2c2 100644 --- a/libgo/go/net/http/transport_windows.go +++ b/libgo/go/net/http/transport_windows.go @@ -6,14 +6,14 @@ package http import ( "net" - "os" + "syscall" ) func init() { remoteSideClosedFunc = func(err error) (out bool) { op, ok := err.(*net.OpError) - if ok && op.Op == "WSARecv" && op.Net == "tcp" && op.Err == os.Errno(10058) { - // TODO(bradfitz): find the symbol for 10058 + if ok && op.Op == "WSARecv" && op.Net == "tcp" && op.Err == syscall.Errno(10058) { + // TODO(brainman,rsc): Fix whatever is generating this. return true } return false diff --git a/libgo/go/net/interface_bsd.go b/libgo/go/net/interface_bsd.go index b026e01..e896d43 100644 --- a/libgo/go/net/interface_bsd.go +++ b/libgo/go/net/interface_bsd.go @@ -20,18 +20,18 @@ import ( func interfaceTable(ifindex int) ([]Interface, error) { var ( tab []byte - e int + e error msgs []syscall.RoutingMessage ift []Interface ) tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("route rib", e) } msgs, e = syscall.ParseRoutingMessage(tab) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("route message", e) } @@ -55,7 +55,7 @@ func newLink(m *syscall.InterfaceMessage) ([]Interface, error) { var ift []Interface sas, e := syscall.ParseRoutingSockaddr(m) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("route sockaddr", e) } @@ -110,18 +110,18 @@ func linkFlags(rawFlags int32) Flags { func interfaceAddrTable(ifindex int) ([]Addr, error) { var ( tab []byte - e int + e error msgs []syscall.RoutingMessage ifat []Addr ) tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("route rib", e) } msgs, e = syscall.ParseRoutingMessage(tab) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("route message", e) } @@ -145,7 +145,7 @@ func newAddr(m *syscall.InterfaceAddrMessage) ([]Addr, error) { var ifat []Addr sas, e := syscall.ParseRoutingSockaddr(m) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("route sockaddr", e) } diff --git a/libgo/go/net/interface_darwin.go b/libgo/go/net/interface_darwin.go index 1472afb..2da447a 100644 --- a/libgo/go/net/interface_darwin.go +++ b/libgo/go/net/interface_darwin.go @@ -17,18 +17,18 @@ import ( func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) { var ( tab []byte - e int + e error msgs []syscall.RoutingMessage ifmat []Addr ) tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifindex) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("route rib", e) } msgs, e = syscall.ParseRoutingMessage(tab) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("route message", e) } @@ -52,7 +52,7 @@ func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) var ifmat []Addr sas, e := syscall.ParseRoutingSockaddr(m) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("route sockaddr", e) } diff --git a/libgo/go/net/interface_freebsd.go b/libgo/go/net/interface_freebsd.go index b0274f6..a12877e 100644 --- a/libgo/go/net/interface_freebsd.go +++ b/libgo/go/net/interface_freebsd.go @@ -17,18 +17,18 @@ import ( func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) { var ( tab []byte - e int + e error msgs []syscall.RoutingMessage ifmat []Addr ) tab, e = syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifindex) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("route rib", e) } msgs, e = syscall.ParseRoutingMessage(tab) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("route message", e) } @@ -52,7 +52,7 @@ func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) var ifmat []Addr sas, e := syscall.ParseRoutingSockaddr(m) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("route sockaddr", e) } diff --git a/libgo/go/net/interface_linux.go b/libgo/go/net/interface_linux.go index cd0339d..96db718 100644 --- a/libgo/go/net/interface_linux.go +++ b/libgo/go/net/interface_linux.go @@ -21,16 +21,16 @@ func interfaceTable(ifindex int) ([]Interface, error) { ift []Interface tab []byte msgs []syscall.NetlinkMessage - e int + e error ) tab, e = syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("netlink rib", e) } msgs, e = syscall.ParseNetlinkMessage(tab) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("netlink message", e) } @@ -42,7 +42,7 @@ func interfaceTable(ifindex int) ([]Interface, error) { ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0])) if ifindex == 0 || ifindex == int(ifim.Index) { attrs, e := syscall.ParseNetlinkRouteAttr(&m) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("netlink routeattr", e) } ifi := newLink(attrs, ifim) @@ -102,27 +102,19 @@ func linkFlags(rawFlags uint32) Flags { // for all network interfaces. Otherwise it returns addresses // for a specific interface. func interfaceAddrTable(ifindex int) ([]Addr, error) { - var ( - tab []byte - e int - err error - ifat []Addr - msgs []syscall.NetlinkMessage - ) - - tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC) - if e != 0 { + tab, e := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC) + if e != nil { return nil, os.NewSyscallError("netlink rib", e) } - msgs, e = syscall.ParseNetlinkMessage(tab) - if e != 0 { + msgs, e := syscall.ParseNetlinkMessage(tab) + if e != nil { return nil, os.NewSyscallError("netlink message", e) } - ifat, err = addrTable(msgs, ifindex) - if err != nil { - return nil, err + ifat, e := addrTable(msgs, ifindex) + if e != nil { + return nil, e } return ifat, nil @@ -139,7 +131,7 @@ func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) { ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0])) if ifindex == 0 || ifindex == int(ifam.Index) { attrs, e := syscall.ParseNetlinkRouteAttr(&m) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("netlink routeattr", e) } ifat = append(ifat, newAddr(attrs, int(ifam.Family))...) diff --git a/libgo/go/net/interface_windows.go b/libgo/go/net/interface_windows.go index a1c8d95..2ed66cd 100644 --- a/libgo/go/net/interface_windows.go +++ b/libgo/go/net/interface_windows.go @@ -39,7 +39,7 @@ func getAdapterList() (*syscall.IpAdapterInfo, error) { func getInterfaceList() ([]syscall.InterfaceInfo, error) { s, e := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("Socket", e) } defer syscall.Closesocket(s) @@ -48,7 +48,7 @@ func getInterfaceList() ([]syscall.InterfaceInfo, error) { ret := uint32(0) size := uint32(unsafe.Sizeof(ii)) e = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("WSAIoctl", e) } c := ret / uint32(unsafe.Sizeof(ii[0])) diff --git a/libgo/go/net/ipsock.go b/libgo/go/net/ipsock.go index 716454d..9234f5a 100644 --- a/libgo/go/net/ipsock.go +++ b/libgo/go/net/ipsock.go @@ -9,7 +9,7 @@ package net var supportsIPv6, supportsIPv4map = probeIPv6Stack() func firstFavoriteAddr(filter func(IP) IP, addrs []string) (addr IP) { - if filter == anyaddr { + if filter == nil { // We'll take any IP address, but since the dialing code // does not yet try multiple addresses, prefer to use // an IPv4 address if possible. This is especially relevant @@ -113,7 +113,7 @@ func hostPortToIP(net, hostport string) (ip IP, iport int, err error) { // Try as an IP address. addr = ParseIP(host) if addr == nil { - filter := anyaddr + var filter func(IP) IP if net != "" && net[len(net)-1] == '4' { filter = ipv4only } diff --git a/libgo/go/net/ipsock_posix.go b/libgo/go/net/ipsock_posix.go index d5b8f21..f0ca7da 100644 --- a/libgo/go/net/ipsock_posix.go +++ b/libgo/go/net/ipsock_posix.go @@ -33,8 +33,8 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) { } for i := range probes { - s, errno := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) - if errno != 0 { + s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) + if err != nil { continue } defer closesocket(s) @@ -42,8 +42,8 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) { if err != nil { continue } - errno = syscall.Bind(s, sa) - if errno != 0 { + err = syscall.Bind(s, sa) + if err != nil { continue } probes[i].ok = true diff --git a/libgo/go/net/lookup_windows.go b/libgo/go/net/lookup_windows.go index 61d8a88..020871b 100644 --- a/libgo/go/net/lookup_windows.go +++ b/libgo/go/net/lookup_windows.go @@ -22,7 +22,7 @@ func lookupProtocol(name string) (proto int, err error) { protoentLock.Lock() defer protoentLock.Unlock() p, e := syscall.GetProtoByName(name) - if e != 0 { + if e != nil { return 0, os.NewSyscallError("GetProtoByName", e) } return int(p.Proto), nil @@ -44,7 +44,7 @@ func LookupIP(name string) (addrs []IP, err error) { hostentLock.Lock() defer hostentLock.Unlock() h, e := syscall.GetHostByName(name) - if e != 0 { + if e != nil { return nil, os.NewSyscallError("GetHostByName", e) } switch h.AddrType { @@ -71,7 +71,7 @@ func LookupPort(network, service string) (port int, err error) { serventLock.Lock() defer serventLock.Unlock() s, e := syscall.GetServByName(service, network) - if e != 0 { + if e != nil { return 0, os.NewSyscallError("GetServByName", e) } return int(syscall.Ntohs(s.Port)), nil @@ -81,7 +81,7 @@ func LookupCNAME(name string) (cname string, err error) { var r *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_CNAME, 0, nil, &r, nil) if e != 0 { - return "", os.NewSyscallError("LookupCNAME", int(e)) + return "", os.NewSyscallError("LookupCNAME", e) } defer syscall.DnsRecordListFree(r, 1) if r != nil && r.Type == syscall.DNS_TYPE_CNAME { @@ -110,7 +110,7 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err var r *syscall.DNSRecord e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &r, nil) if e != 0 { - return "", nil, os.NewSyscallError("LookupSRV", int(e)) + return "", nil, os.NewSyscallError("LookupSRV", e) } defer syscall.DnsRecordListFree(r, 1) addrs = make([]*SRV, 0, 10) @@ -126,7 +126,7 @@ func LookupMX(name string) (mx []*MX, err error) { var r *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &r, nil) if e != 0 { - return nil, os.NewSyscallError("LookupMX", int(e)) + return nil, os.NewSyscallError("LookupMX", e) } defer syscall.DnsRecordListFree(r, 1) mx = make([]*MX, 0, 10) @@ -142,7 +142,7 @@ func LookupTXT(name string) (txt []string, err error) { var r *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_TEXT, 0, nil, &r, nil) if e != 0 { - return nil, os.NewSyscallError("LookupTXT", int(e)) + return nil, os.NewSyscallError("LookupTXT", e) } defer syscall.DnsRecordListFree(r, 1) txt = make([]string, 0, 10) @@ -164,7 +164,7 @@ func LookupAddr(addr string) (name []string, err error) { var r *syscall.DNSRecord e := syscall.DnsQuery(arpa, syscall.DNS_TYPE_PTR, 0, nil, &r, nil) if e != 0 { - return nil, os.NewSyscallError("LookupAddr", int(e)) + return nil, os.NewSyscallError("LookupAddr", e) } defer syscall.DnsRecordListFree(r, 1) name = make([]string, 0, 10) diff --git a/libgo/go/net/newpollserver.go b/libgo/go/net/newpollserver.go index 9ad6f7b..035df4a 100644 --- a/libgo/go/net/newpollserver.go +++ b/libgo/go/net/newpollserver.go @@ -18,11 +18,10 @@ func newPollServer() (s *pollServer, err error) { if s.pr, s.pw, err = os.Pipe(); err != nil { return nil, err } - var e int - if e = syscall.SetNonblock(s.pr.Fd(), true); e != 0 { + if err = syscall.SetNonblock(s.pr.Fd(), true); err != nil { goto Errno } - if e = syscall.SetNonblock(s.pw.Fd(), true); e != 0 { + if err = syscall.SetNonblock(s.pw.Fd(), true); err != nil { goto Errno } if s.poll, err = newpollster(); err != nil { @@ -37,7 +36,7 @@ func newPollServer() (s *pollServer, err error) { return s, nil Errno: - err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)} + err = &os.PathError{"setnonblock", s.pr.Name(), err} Error: s.pr.Close() s.pw.Close() diff --git a/libgo/go/net/pipe.go b/libgo/go/net/pipe.go index b99e6e6..0ce7ccb 100644 --- a/libgo/go/net/pipe.go +++ b/libgo/go/net/pipe.go @@ -1,3 +1,7 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package net import ( diff --git a/libgo/go/net/sendfile_linux.go b/libgo/go/net/sendfile_linux.go index 36c7578..350abe4 100644 --- a/libgo/go/net/sendfile_linux.go +++ b/libgo/go/net/sendfile_linux.go @@ -62,18 +62,18 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { written += int64(n) remain -= int64(n) } - if n == 0 && errno == 0 { + if n == 0 && errno == nil { break } if errno == syscall.EAGAIN && c.wdeadline >= 0 { pollserver.WaitWrite(c) continue } - if errno != 0 { + if errno != nil { // This includes syscall.ENOSYS (no kernel // support) and syscall.EINVAL (fd types which // don't implement sendfile together) - err = &OpError{"sendfile", c.net, c.raddr, os.Errno(errno)} + err = &OpError{"sendfile", c.net, c.raddr, errno} break } } diff --git a/libgo/go/net/sendfile_windows.go b/libgo/go/net/sendfile_windows.go index 0b31572..ee7ff8b 100644 --- a/libgo/go/net/sendfile_windows.go +++ b/libgo/go/net/sendfile_windows.go @@ -16,7 +16,7 @@ type sendfileOp struct { n uint32 } -func (o *sendfileOp) Submit() (errno int) { +func (o *sendfileOp) Submit() (err error) { return syscall.TransmitFile(o.fd.sysfd, o.src, o.n, 0, &o.o, nil, syscall.TF_WRITE_BEHIND) } diff --git a/libgo/go/net/sock.go b/libgo/go/net/sock.go index d9df02c..33f11f2 100644 --- a/libgo/go/net/sock.go +++ b/libgo/go/net/sock.go @@ -28,9 +28,9 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal // See ../syscall/exec.go for description of ForkLock. syscall.ForkLock.RLock() s, e := syscall.Socket(f, p, t) - if e != 0 { + if err != nil { syscall.ForkLock.RUnlock() - return nil, os.Errno(e) + return nil, err } syscall.CloseOnExec(s) syscall.ForkLock.RUnlock() @@ -39,9 +39,9 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal if la != nil { e = syscall.Bind(s, la) - if e != 0 { + if e != nil { closesocket(s) - return nil, os.Errno(e) + return nil, e } } diff --git a/libgo/go/net/tcpsock_posix.go b/libgo/go/net/tcpsock_posix.go index a726b45..44890ba 100644 --- a/libgo/go/net/tcpsock_posix.go +++ b/libgo/go/net/tcpsock_posix.go @@ -250,9 +250,9 @@ func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err error) { return nil, err } errno := syscall.Listen(fd.sysfd, listenBacklog()) - if errno != 0 { + if errno != nil { closesocket(fd.sysfd) - return nil, &OpError{"listen", "tcp", laddr, os.Errno(errno)} + return nil, &OpError{"listen", "tcp", laddr, errno} } l = new(TCPListener) l.fd = fd diff --git a/libgo/go/net/unixsock_posix.go b/libgo/go/net/unixsock_posix.go index 6ba692e..929f640 100644 --- a/libgo/go/net/unixsock_posix.go +++ b/libgo/go/net/unixsock_posix.go @@ -327,9 +327,9 @@ func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err error) { return nil, err } e1 := syscall.Listen(fd.sysfd, 8) // listenBacklog()); - if e1 != 0 { + if e1 != nil { closesocket(fd.sysfd) - return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Err: os.Errno(e1)} + return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Err: e1} } return &UnixListener{fd, laddr.Name}, nil } |