github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/httputil/client.go (about) 1 // Copyright 2019 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package httputil 12 13 import ( 14 "context" 15 "io" 16 "net" 17 "net/http" 18 "time" 19 ) 20 21 // DefaultClient is a replacement for http.DefaultClient which defines 22 // a standard timeout. 23 var DefaultClient = NewClientWithTimeout(standardHTTPTimeout) 24 25 const standardHTTPTimeout time.Duration = 3 * time.Second 26 27 // NewClientWithTimeout defines a http.Client with the given timeout. 28 func NewClientWithTimeout(timeout time.Duration) *Client { 29 return &Client{&http.Client{ 30 Timeout: timeout, 31 Transport: &http.Transport{ 32 // Don't leak a goroutine on OSX (the TCP level timeout is probably 33 // much higher than on linux). 34 DialContext: (&net.Dialer{Timeout: timeout}).DialContext, 35 DisableKeepAlives: true, 36 }, 37 }} 38 } 39 40 // Client is a replacement for http.Client which implements method 41 // variants that respect a provided context's cancellation status. 42 type Client struct { 43 *http.Client 44 } 45 46 // Get does like http.Get but uses the provided context and obeys its cancellation. 47 // It also uses the default client with a default 3 second timeout. 48 func Get(ctx context.Context, url string) (resp *http.Response, err error) { 49 return DefaultClient.Get(ctx, url) 50 } 51 52 // Head does like http.Head but uses the provided context and obeys its cancellation. 53 // It also uses the default client with a default 3 second timeout. 54 func Head(ctx context.Context, url string) (resp *http.Response, err error) { 55 return DefaultClient.Head(ctx, url) 56 } 57 58 // Post does like http.Post but uses the provided context and obeys its cancellation. 59 // It also uses the default client with a default 3 second timeout. 60 func Post( 61 ctx context.Context, url, contentType string, body io.Reader, 62 ) (resp *http.Response, err error) { 63 return DefaultClient.Post(ctx, url, contentType, body) 64 } 65 66 // Get does like http.Client.Get but uses the provided context and obeys its cancellation. 67 func (c *Client) Get(ctx context.Context, url string) (resp *http.Response, err error) { 68 req, err := NewRequestWithContext(ctx, "GET", url, nil) 69 if err != nil { 70 return nil, err 71 } 72 return c.Do(req) 73 } 74 75 // Head does like http.Client.Head but uses the provided context and obeys its cancellation. 76 func (c *Client) Head(ctx context.Context, url string) (resp *http.Response, err error) { 77 req, err := NewRequestWithContext(ctx, "HEAD", url, nil) 78 if err != nil { 79 return nil, err 80 } 81 return c.Do(req) 82 } 83 84 // Post does like http.Client.Post but uses the provided context and obeys its cancellation. 85 func (c *Client) Post( 86 ctx context.Context, url, contentType string, body io.Reader, 87 ) (resp *http.Response, err error) { 88 req, err := NewRequestWithContext(ctx, "POST", url, body) 89 if err != nil { 90 return nil, err 91 } 92 req.Header.Set("Content-Type", contentType) 93 return c.Do(req) 94 }