diff --git a/acme/api/api.go b/acme/api/api.go index 6d2a7f0b9..19c06814e 100644 --- a/acme/api/api.go +++ b/acme/api/api.go @@ -47,6 +47,10 @@ func New(httpClient *http.Client, userAgent, caDirURL, kid string, privateKey cr return nil, err } + return newCore(httpClient, doer, dir, kid, privateKey) +} + +func newCore(httpClient *http.Client, doer *sender.Doer, dir acme.Directory, kid string, privateKey crypto.Signer) (*Core, error) { nonceManager := nonces.NewManager(doer, dir.NewNonceURL) c := &Core{ @@ -57,6 +61,7 @@ func New(httpClient *http.Client, userAgent, caDirURL, kid string, privateKey cr privateKey: privateKey, kid: kid, + // NOTE(ldez): use the doer instead of the HTTP client? (only related to OCSP) HTTPClient: httpClient, } @@ -167,10 +172,14 @@ func (a *Core) GetDirectory() acme.Directory { func getDirectory(ctx context.Context, do *sender.Doer, caDirURL string) (acme.Directory, error) { var dir acme.Directory - if _, err := do.Get(ctx, caDirURL, &dir); err != nil { + + resp, err := do.Get(ctx, caDirURL, &dir) + if err != nil { return dir, fmt.Errorf("get directory at '%s': %w", caDirURL, err) } + defer func() { _ = resp.Body.Close() }() + if dir.NewAccountURL == "" { return dir, errors.New("directory missing new registration URL") } diff --git a/acme/api/certificate_renewal.go b/acme/api/certificate_renewal.go index 57d2049ef..24f3d524c 100644 --- a/acme/api/certificate_renewal.go +++ b/acme/api/certificate_renewal.go @@ -5,10 +5,8 @@ import ( "crypto/x509" "encoding/asn1" "encoding/base64" - "encoding/json" "errors" "fmt" - "net/http" "github.com/go-acme/lego/v5/acme" ) @@ -32,25 +30,15 @@ func (c *CertificateService) GetRenewalInfo(ctx context.Context, certID string) return nil, errors.New("renewalInfo[get]: 'certID' cannot be empty") } - req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.core.GetDirectory().RenewalInfo+"/"+certID, nil) - if err != nil { - return nil, err - } + info := new(acme.ExtendedRenewalInfo) - resp, err := c.core.HTTPClient.Do(req) + resp, err := c.core.doer.Get(ctx, c.core.GetDirectory().RenewalInfo+"/"+certID, info) if err != nil { return nil, err } defer func() { _ = resp.Body.Close() }() - info := new(acme.ExtendedRenewalInfo) - - err = json.NewDecoder(resp.Body).Decode(info) - if err != nil { - return nil, err - } - if retry := resp.Header.Get("Retry-After"); retry != "" { info.RetryAfter, err = ParseRetryAfter(retry) if err != nil { diff --git a/acme/api/certificate_renewal_test.go b/acme/api/certificate_renewal_test.go index 634828569..401345e55 100644 --- a/acme/api/certificate_renewal_test.go +++ b/acme/api/certificate_renewal_test.go @@ -50,8 +50,7 @@ func TestCertificateService_GetRenewalInfo(t *testing.T) { "end": "2020-03-17T18:21:09Z" }, "explanationUrl": "https://aricapable.ca.example/docs/renewal-advice/" - } - }`). + }`). WithHeader("Content-Type", "application/json"). WithHeader("Retry-After", "21600")). BuildHTTPS(t) @@ -83,8 +82,7 @@ func TestCertificateService_GetRenewalInfo_retryAfter(t *testing.T) { "end": "2020-03-17T18:21:09Z" }, "explanationUrl": "https://aricapable.ca.example/docs/renewal-advice/" - } - }`). + }`). WithHeader("Content-Type", "application/json"). WithHeader("Retry-After", time.Now().UTC().Add(6*time.Hour).Format(time.RFC1123))). BuildHTTPS(t) diff --git a/acme/api/internal/nonces/nonce_manager.go b/acme/api/internal/nonces/nonce_manager.go index 1d2447c60..9a7271c89 100644 --- a/acme/api/internal/nonces/nonce_manager.go +++ b/acme/api/internal/nonces/nonce_manager.go @@ -61,6 +61,8 @@ func (n *Manager) getNonce(ctx context.Context) (string, error) { return "", fmt.Errorf("failed to get nonce from HTTP HEAD: %w", err) } + defer func() { _ = resp.Body.Close() }() + return GetFromResponse(resp) } diff --git a/acme/api/internal/sender/sender.go b/acme/api/internal/sender/sender.go index f9949a7cc..bc11fba54 100644 --- a/acme/api/internal/sender/sender.go +++ b/acme/api/internal/sender/sender.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/go-acme/lego/v5/acme" + "github.com/go-acme/lego/v5/internal/errutils" ) type RequestOption func(*http.Request) error @@ -90,7 +91,7 @@ func (d *Doer) newRequest(ctx context.Context, method, uri string, body io.Reade func (d *Doer) do(req *http.Request, response any) (*http.Response, error) { resp, err := d.httpClient.Do(req) if err != nil { - return nil, err + return nil, errutils.NewHTTPDoError(req, err) } if err = checkError(req, resp); err != nil { @@ -100,14 +101,14 @@ func (d *Doer) do(req *http.Request, response any) (*http.Response, error) { if response != nil { raw, err := io.ReadAll(resp.Body) if err != nil { - return resp, err + return resp, errutils.NewReadResponseError(req, resp.StatusCode, err) } defer resp.Body.Close() err = json.Unmarshal(raw, response) if err != nil { - return resp, fmt.Errorf("failed to unmarshal %q to type %T: %w", raw, response, err) + return resp, errutils.NewUnmarshalError(req, resp.StatusCode, raw, err) } }