package toolkit import ( "net/http" "net/http/httputil" "net/url" "dev.mediocregopher.com/mediocre-go-lib.git/mlog" "github.com/tv42/httpunix" ) // HTTPClient is an interface around the default http.Client type. type HTTPClient interface { Do(*http.Request) (*http.Response, error) // Close cleans up any resources being held by the HTTPClient. Close() error } type httpClient struct { logger *mlog.Logger *http.Client } // NewHTTPClient returns a new HTTPClient using a clone of // [http.DefaultTransport]. func NewHTTPClient(logger *mlog.Logger) HTTPClient { return &httpClient{ logger, &http.Client{ Transport: http.DefaultTransport.(*http.Transport).Clone(), }, } } // NewUnixHTTPClient returns an HTTPClient which will use the given // unixSocketPath to serve requests. The base URL (scheme and host) which should // be used for requests is returned as well. func NewUnixHTTPClient( logger *mlog.Logger, unixSocketPath string, ) ( HTTPClient, *url.URL, ) { const host = "uds" u := &url.URL{ Scheme: httpunix.Scheme, Host: host, } transport := new(httpunix.Transport) transport.RegisterLocation(host, unixSocketPath) return &httpClient{logger, &http.Client{Transport: transport}}, u } func (c *httpClient) Do(req *http.Request) (*http.Response, error) { if c.logger.MaxLevel() < mlog.LevelDebug.Int() { return c.Client.Do(req) } var ( ctx = req.Context() origScheme = req.URL.Scheme ) // httputil.DumpRequestOut doesn't like the httpunix.Scheme, so we // temporarily switch it. if req.URL.Scheme == httpunix.Scheme { req.URL.Scheme = "http" } reqB, err := httputil.DumpRequestOut(req, true) if err != nil { c.logger.Error(ctx, "failed to dump http request", err) } else { c.logger.Debug(ctx, "------ request ------\n"+string(reqB)+"\n") } req.URL.Scheme = origScheme res, err := c.Client.Do(req) if res != nil { resB, err := httputil.DumpResponse(res, true) if err != nil { c.logger.Error(ctx, "failed to dump http response", err) } else { c.logger.Debug(ctx, "------ response ------\n"+string(resB)+"\n") } } return res, err } func (c *httpClient) Close() error { c.CloseIdleConnections() return nil }