Andrey Meshkov 87137bddcf Sync v2.10.0
2024-11-08 16:26:22 +03:00

106 lines
2.5 KiB
Go

package agdhttp
import (
"context"
"fmt"
"io"
"net/http"
"net/url"
"time"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/golibs/httphdr"
"github.com/AdguardTeam/golibs/netutil/urlutil"
)
// Client is a wrapper around http.Client.
type Client struct {
http *http.Client
userAgent string
}
// ClientConfig is the configuration structure for Client.
type ClientConfig struct {
// Timeout is the timeout for all requests.
Timeout time.Duration
}
// NewClient returns a new client. c must not be nil.
func NewClient(conf *ClientConfig) (c *Client) {
return &Client{
http: &http.Client{
Timeout: conf.Timeout,
},
userAgent: UserAgent(),
}
}
// Get is a wrapper around [http.Client.Get].
//
// When err is nil, resp always contains a non-nil resp.Body. Caller should
// close resp.Body when done reading from it.
func (c *Client) Get(ctx context.Context, u *url.URL) (resp *http.Response, err error) {
return c.do(ctx, http.MethodGet, u, "", nil)
}
// Post is a wrapper around [http.Client.Post].
//
// When err is nil, resp always contains a non-nil resp.Body. Caller should
// close resp.Body when done reading from it.
func (c *Client) Post(
ctx context.Context,
u *url.URL,
contentType string,
body io.Reader,
) (resp *http.Response, err error) {
return c.do(ctx, http.MethodPost, u, contentType, body)
}
// Put is a wrapper around [http.Client.Put].
//
// When err is nil, resp always contains a non-nil resp.Body. Caller should
// close resp.Body when done reading from it.
func (c *Client) Put(
ctx context.Context,
u *url.URL,
contentType string,
body io.Reader,
) (resp *http.Response, err error) {
return c.do(ctx, http.MethodPut, u, contentType, body)
}
// do is a wrapper around [http.Client.Do].
func (c *Client) do(
ctx context.Context,
method string,
u *url.URL,
contentType string,
body io.Reader,
) (resp *http.Response, err error) {
req, err := http.NewRequestWithContext(ctx, method, u.String(), body)
if err != nil {
return nil, fmt.Errorf("creating %s request to: %w", method, err)
}
if contentType != "" {
req.Header.Set(httphdr.ContentType, contentType)
}
reqID, ok := agd.RequestIDFromContext(ctx)
if ok {
req.Header.Set(httphdr.XRequestID, reqID.String())
}
req.Header.Set(httphdr.UserAgent, c.userAgent)
resp, err = c.http.Do(req)
urlutil.RedactUserinfoInURLError(u, err)
if err != nil && resp != nil && resp.Header != nil {
// A non-nil Response with a non-nil error only occurs when
// CheckRedirect fails.
return resp, WrapServerError(err, resp)
}
return resp, err
}