66 lines
1.7 KiB
Go
66 lines
1.7 KiB
Go
package acme
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
)
|
|
|
|
// Problem document as defined in,
|
|
// https://tools.ietf.org/html/rfc7807
|
|
|
|
// Problem represents an error returned by an acme server.
|
|
type Problem struct {
|
|
Type string `json:"type"`
|
|
Detail string `json:"detail,omitempty"`
|
|
Status int `json:"status,omitempty"`
|
|
Instance string `json:"instance,omitempty"`
|
|
SubProblems []SubProblem `json:"subproblems,omitempty"`
|
|
}
|
|
|
|
type SubProblem struct {
|
|
Type string `json:"type"`
|
|
Detail string `json:"detail"`
|
|
Identifier Identifier `json:"identifier"`
|
|
}
|
|
|
|
// Returns a human readable error string.
|
|
func (err Problem) Error() string {
|
|
s := fmt.Sprintf("acme: error code %d %q: %s", err.Status, err.Type, err.Detail)
|
|
if len(err.SubProblems) > 0 {
|
|
for _, v := range err.SubProblems {
|
|
s += fmt.Sprintf(", problem %q: %s", v.Type, v.Detail)
|
|
}
|
|
}
|
|
if err.Instance != "" {
|
|
s += ", url: " + err.Instance
|
|
}
|
|
return s
|
|
}
|
|
|
|
// Helper function to determine if a response contains an expected status code, or otherwise an error object.
|
|
func checkError(resp *http.Response, expectedStatuses ...int) error {
|
|
for _, statusCode := range expectedStatuses {
|
|
if resp.StatusCode == statusCode {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
if resp.StatusCode < 400 || resp.StatusCode >= 600 {
|
|
return fmt.Errorf("acme: expected status codes: %d, got: %d %s", expectedStatuses, resp.StatusCode, resp.Status)
|
|
}
|
|
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return fmt.Errorf("acme: error reading error body: %v", err)
|
|
}
|
|
|
|
acmeError := Problem{}
|
|
if err := json.Unmarshal(body, &acmeError); err != nil {
|
|
return fmt.Errorf("acme: parsing error body: %v - %s", err, string(body))
|
|
}
|
|
|
|
return acmeError
|
|
}
|