Skip to content

Instantly share code, notes, and snippets.

@decoomanj
Forked from seantalts/httpclient.go
Created October 11, 2017 10:33
Show Gist options
  • Select an option

  • Save decoomanj/c85e5f6540936b7c6b32ecc59a0c3e95 to your computer and use it in GitHub Desktop.

Select an option

Save decoomanj/c85e5f6540936b7c6b32ecc59a0c3e95 to your computer and use it in GitHub Desktop.
package json_client
import (
"net"
"time"
)
type TimeoutConn struct {
net.Conn
timeout time.Duration
}
func NewTimeoutConn(conn net.Conn, timeout time.Duration) *TimeoutConn {
return &TimeoutConn{
Conn: conn,
timeout: timeout,
}
}
func (c *TimeoutConn) Read(b []byte) (n int, err error) {
c.SetReadDeadline(time.Now().Add(c.timeout))
return c.Conn.Read(b)
}
func (c *TimeoutConn) Write(b []byte) (n int, err error) {
c.SetWriteDeadline(time.Now().Add(c.timeout))
return c.Conn.Write(b)
}
type dialer func(netw, addr string) (net.Conn, error)
func NewTimeoutDial(readWriteTimeout, dialTimeout time.Duration) dialer {
return func(netw, addr string) (net.Conn, error) {
conn, err := net.DialTimeout(netw, addr, dialTimeout)
if err != nil {
return nil, err
}
return NewTimeoutConn(conn, readWriteTimeout), nil
}
}
package json_client
import (
"io"
"io/ioutil"
"net"
"net/http"
"net/http/httptest"
"testing"
"time"
)
func TestHttpTimeout(t *testing.T) {
http.HandleFunc("/normal", func(w http.ResponseWriter, req *http.Request) {
// Empirically, timeouts less than these seem to be flaky
time.Sleep(100 * time.Millisecond)
io.WriteString(w, "ok")
})
http.HandleFunc("/timeout", func(w http.ResponseWriter, req *http.Request) {
time.Sleep(250 * time.Millisecond)
io.WriteString(w, "ok")
})
ts := httptest.NewServer(http.DefaultServeMux)
defer ts.Close()
numDials := 0
client := &http.Client{
Transport: &http.Transport{
Dial: func(netw, addr string) (net.Conn, error) {
t.Logf("dial to %s://%s", netw, addr)
numDials++
return NewTimeoutDial(time.Millisecond*200, time.Millisecond*200)(netw,
addr)
},
},
}
addr := ts.URL
SendTestRequest(t, client, "1st", addr, "normal")
SendTestRequest(t, client, "2st", addr, "normal")
SendTestRequest(t, client, "3st", addr, "timeout")
SendTestRequest(t, client, "4st", addr, "normal")
time.Sleep(time.Millisecond * 300)
SendTestRequest(t, client, "5st", addr, "normal")
if numDials
}
func SendTestRequest(t *testing.T, client *http.Client, id, addr, path string) {
req, err := http.NewRequest("GET", addr+"/"+path, nil)
if err != nil {
t.Fatalf("new request failed - %s", err)
}
req.Header.Add("Connection", "keep-alive")
switch path {
case "normal":
if resp, err := client.Do(req); err != nil {
t.Fatalf("%s request failed - %s", id, err)
} else {
result, err2 := ioutil.ReadAll(resp.Body)
if err2 != nil {
t.Fatalf("%s response read failed - %s", id, err2)
}
resp.Body.Close()
t.Logf("%s request - %s", id, result)
}
case "timeout":
if _, err := client.Do(req); err == nil {
t.Fatalf("%s request not timeout", id)
} else {
t.Logf("%s request - %s", id, err)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment