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  }