// Copyright 2019 Yunion // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package httputils import ( "net" "time" ) type connDelegate struct { conn net.Conn socketTimeout time.Duration finalTimeout time.Duration } func getConnDelegate(conn net.Conn, socketTimeout, finalTimeout time.Duration) *connDelegate { return &connDelegate{ conn: conn, socketTimeout: socketTimeout, finalTimeout: finalTimeout, } } func (delegate *connDelegate) Read(b []byte) (n int, err error) { delegate.SetReadDeadline(time.Now().Add(delegate.socketTimeout)) n, err = delegate.conn.Read(b) delegate.SetReadDeadline(time.Now().Add(delegate.finalTimeout)) return n, err } func (delegate *connDelegate) Write(b []byte) (n int, err error) { delegate.SetWriteDeadline(time.Now().Add(delegate.socketTimeout)) n, err = delegate.conn.Write(b) finalTimeout := time.Now().Add(delegate.finalTimeout) delegate.SetWriteDeadline(finalTimeout) delegate.SetReadDeadline(finalTimeout) return n, err } func (delegate *connDelegate) Close() error { return delegate.conn.Close() } func (delegate *connDelegate) LocalAddr() net.Addr { return delegate.conn.LocalAddr() } func (delegate *connDelegate) RemoteAddr() net.Addr { return delegate.conn.RemoteAddr() } // SetDeadline sets the read and write deadlines associated // with the connection. It is equivalent to calling both // SetReadDeadline and SetWriteDeadline. // // A deadline is an absolute time after which I/O operations // fail with a timeout (see type Error) instead of // blocking. The deadline applies to all future and pending // I/O, not just the immediately following call to Read or // Write. After a deadline has been exceeded, the connection // can be refreshed by setting a deadline in the future. // // An idle timeout can be implemented by repeatedly extending // the deadline after successful Read or Write calls. // // A zero value for t means I/O operations will not time out. // // Note that if a TCP connection has keep-alive turned on, // which is the default unless overridden by Dialer.KeepAlive // or ListenConfig.KeepAlive, then a keep-alive failure may // also return a timeout error. On Unix systems a keep-alive // failure on I/O can be detected using // errors.Is(err, syscall.ETIMEDOUT). func (delegate *connDelegate) SetDeadline(t time.Time) error { return delegate.conn.SetDeadline(t) } // SetReadDeadline sets the deadline for future Read calls // and any currently-blocked Read call. // A zero value for t means Read will not time out. func (delegate *connDelegate) SetReadDeadline(t time.Time) error { return delegate.conn.SetReadDeadline(t) } // SetWriteDeadline sets the deadline for future Write calls // and any currently-blocked Write call. // Even if write times out, it may return n > 0, indicating that // some of the data was successfully written. // A zero value for t means Write will not time out. func (delegate *connDelegate) SetWriteDeadline(t time.Time) error { return delegate.conn.SetWriteDeadline(t) }