Skip to content

Instantly share code, notes, and snippets.

@c4milo
Last active August 3, 2017 05:35
Show Gist options
  • Save c4milo/275abc6eccbfd88ad56ca7c77947883a to your computer and use it in GitHub Desktop.
Save c4milo/275abc6eccbfd88ad56ca7c77947883a to your computer and use it in GitHub Desktop.
HTTP client with support for read and write timeouts which are missing in Go's standard library.
package httpclient
import (
"context"
"net"
"net/http"
"time"
)
// DialContextFn was defined to make code more readable.
type dialContextFn func(ctx context.Context, network, address string) (net.Conn, error)
// DialContext implements our own dialer in order to set read and write idle timeouts.
func DialContext(rwtimeout, ctimeout time.Duration) dialContextFn {
dialer := &net.Dialer{Timeout: ctimeout}
return func(ctx context.Context, network, addr string) (net.Conn, error) {
c, err := dialer.DialContext(ctx, network, addr)
if err != nil {
return nil, err
}
if rwtimeout > 0 {
timeoutConn := &tcpConn{
TCPConn: c.(*net.TCPConn),
timeout: rwtimeout,
}
return timeoutConn, nil
}
return c, nil
}
}
// tcpConn is our own net.Conn which sets a read and write deadline and resets them each
// time there is read or write activity in the connection.
type tcpConn struct {
*net.TCPConn
timeout time.Duration
}
func (c *tcpConn) Read(b []byte) (int, error) {
err := c.TCPConn.SetDeadline(time.Now().Add(c.timeout))
if err != nil {
return 0, err
}
return c.TCPConn.Read(b)
}
func (c *tcpConn) Write(b []byte) (int, error) {
err := c.TCPConn.SetDeadline(time.Now().Add(c.timeout))
if err != nil {
return 0, err
}
return c.TCPConn.Write(b)
}
// DefaultClient returns a default client with sensible values for slow 3G connections and above.
func DefaultClient() *http.Client {
return &http.Client{
Transport: &http.Transport{
DialContext: DialContext(30*time.Second, 10*time.Second),
Proxy: http.ProxyFromEnvironment,
MaxIdleConns: 100,
IdleConnTimeout: 30 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
ResponseHeaderTimeout: 10 * time.Second,
},
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment