Skip to content

Instantly share code, notes, and snippets.

@xeoncross
Forked from dmichael/httpclient.go
Created March 31, 2014 22:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xeoncross/9904166 to your computer and use it in GitHub Desktop.
Save xeoncross/9904166 to your computer and use it in GitHub Desktop.
package httpclient
import (
"net"
"net/http"
"time"
)
type Config struct {
ConnectTimeout time.Duration
ReadWriteTimeout time.Duration
}
func TimeoutDialer(config *Config) func(net, addr string) (c net.Conn, err error) {
return func(netw, addr string) (net.Conn, error) {
conn, err := net.DialTimeout(netw, addr, config.ConnectTimeout)
if err != nil {
return nil, err
}
conn.SetDeadline(time.Now().Add(config.ReadWriteTimeout))
return conn, nil
}
}
func NewTimeoutClient(args ...interface{}) *http.Client {
// Default configuration
config := &Config{
ConnectTimeout: 1 * time.Second,
ReadWriteTimeout: 1 * time.Second,
}
// merge the default with user input if there is one
if len(args) == 1 {
timeout := args[0].(time.Duration)
config.ConnectTimeout = timeout
config.ReadWriteTimeout = timeout
}
if len(args) == 2 {
config.ConnectTimeout = args[0].(time.Duration)
config.ReadWriteTimeout = args[1].(time.Duration)
}
return &http.Client{
Transport: &http.Transport{
Dial: TimeoutDialer(config),
},
}
}
package httpclient
import (
"io"
"net"
"net/http"
"sync"
"testing"
"time"
)
var starter sync.Once
var addr net.Addr
func testHandler(w http.ResponseWriter, req *http.Request) {
time.Sleep(500 * time.Millisecond)
io.WriteString(w, "hello, world!\n")
}
func testDelayedHandler(w http.ResponseWriter, req *http.Request) {
time.Sleep(2100 * time.Millisecond)
io.WriteString(w, "hello, world ... in a bit\n")
}
func setupMockServer(t *testing.T) {
http.HandleFunc("/test", testHandler)
http.HandleFunc("/test-delayed", testDelayedHandler)
ln, err := net.Listen("tcp", ":0")
if err != nil {
t.Fatalf("failed to listen - %s", err.Error())
}
go func() {
err = http.Serve(ln, nil)
if err != nil {
t.Fatalf("failed to start HTTP server - %s", err.Error())
}
}()
addr = ln.Addr()
}
func TestDefaultConfig(t *testing.T) {
starter.Do(func() { setupMockServer(t) })
httpClient := NewTimeoutClient()
req, _ := http.NewRequest("GET", "http://"+addr.String()+"/test-delayed", nil)
httpClient = NewTimeoutClient()
_, err := httpClient.Do(req)
if err == nil {
t.Fatalf("request should have timed out")
}
}
func TestHttpClient(t *testing.T) {
starter.Do(func() { setupMockServer(t) })
httpClient := NewTimeoutClient()
req, _ := http.NewRequest("GET", "http://"+addr.String()+"/test", nil)
resp, err := httpClient.Do(req)
if err != nil {
t.Fatalf("1st request failed - %s", err.Error())
}
defer resp.Body.Close()
connectTimeout := (250 * time.Millisecond)
readWriteTimeout := (50 * time.Millisecond)
httpClient = NewTimeoutClient(connectTimeout, readWriteTimeout)
resp, err = httpClient.Do(req)
if err == nil {
t.Fatalf("2nd request should have timed out")
}
resp, err = httpClient.Do(req)
if resp != nil {
t.Fatalf("3nd request should not have timed out")
}
}
/*
This wrapper takes care of both the connection timeout and the readwrite timeout.
WARNING: You must instantiate this every time you want to use it, otherwise it is
likely that the timeout is reached before you actually make the call.
One argument sets the connect timeout and the readwrite timeout to the same value.
Other wise, 2 arguments are 1) connect and 2) readwrite
It returns an *http.Client
*/
package main
import(
"httpclient"
"time"
)
func main() {
httpClient := httpclient.NewWithTimeout(500*time.Millisecond, 1*time.Second)
resp, err := httpClient.Get("http://google.com")
if err != nil {
fmt.Println("Rats! Google is down.")
}
}
@xeoncross
Copy link
Author

Setting headers:

package main

import (
    "fmt"
    "net/http"
    "io/ioutil"
    "os"
)

func main() {

    url := "http://example.com"

    request, err := http.NewRequest("GET", url, nil)
    if err != nil {
        fmt.Printf("%s", err)
        os.Exit(1)
    }
    request.Header.Set("User-Agent", "value")

    client := &http.Client{}
    response, err := client.Do(request)

    if err != nil {
        fmt.Printf("%s", err)
        os.Exit(1)
    }

    defer response.Body.Close()

    contents, err := ioutil.ReadAll(response.Body)

    if err != nil {
        fmt.Printf("%s", err)
        os.Exit(1)
    }

    fmt.Printf("%s\n", string(contents))
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment