traefik/vendor/github.com/edeckers/auroradnsclient/requests/requestor.go
2018-01-22 12:16:03 +01:00

124 lines
3.2 KiB
Go

package requests
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/http/httputil"
"time"
request_errors "github.com/edeckers/auroradnsclient/requests/errors"
"github.com/edeckers/auroradnsclient/tokens"
"github.com/sirupsen/logrus"
)
// AuroraRequestor performs actual requests to API
type AuroraRequestor struct {
endpoint string
userID string
key string
}
// NewAuroraRequestor instantiates a new requestor
func NewAuroraRequestor(endpoint string, userID string, key string) (*AuroraRequestor, error) {
if endpoint == "" {
return nil, fmt.Errorf("Aurora endpoint missing")
}
if userID == "" || key == "" {
return nil, fmt.Errorf("Aurora credentials missing")
}
return &AuroraRequestor{endpoint: endpoint, userID: userID, key: key}, nil
}
func (requestor *AuroraRequestor) buildRequest(relativeURL string, method string, body []byte) (*http.Request, error) {
url := fmt.Sprintf("%s/%s", requestor.endpoint, relativeURL)
request, err := http.NewRequest(method, url, bytes.NewReader(body))
if err != nil {
logrus.Errorf("Failed to build request: %s", err)
return request, err
}
timestamp := time.Now().UTC()
fmtTime := timestamp.Format("20060102T150405Z")
token := tokens.NewToken(requestor.userID, requestor.key, method, fmt.Sprintf("/%s", relativeURL), timestamp)
request.Header.Set("X-AuroraDNS-Date", fmtTime)
request.Header.Set("Authorization", fmt.Sprintf("AuroraDNSv1 %s", token))
request.Header.Set("Content-Type", "application/json")
rawRequest, err := httputil.DumpRequestOut(request, true)
if err != nil {
logrus.Errorf("Failed to dump request: %s", err)
}
logrus.Debugf("Built request:\n%s", rawRequest)
return request, err
}
func (requestor *AuroraRequestor) testInvalidResponse(resp *http.Response, response []byte) ([]byte, error) {
if resp.StatusCode < 400 {
return response, nil
}
logrus.Errorf("Received invalid status code %d:\n%s", resp.StatusCode, response)
content := errors.New(string(response))
statusCodeErrorMap := map[int]error{
400: request_errors.BadRequest(content),
401: request_errors.Unauthorized(content),
403: request_errors.Forbidden(content),
404: request_errors.NotFound(content),
500: request_errors.ServerError(content),
}
mappedError := statusCodeErrorMap[resp.StatusCode]
if mappedError == nil {
return nil, request_errors.InvalidStatusCodeError(content)
}
return nil, mappedError
}
// Request builds and executues a request to the API
func (requestor *AuroraRequestor) Request(relativeURL string, method string, body []byte) ([]byte, error) {
req, err := requestor.buildRequest(relativeURL, method, body)
client := http.Client{Timeout: 30 * time.Second}
resp, err := client.Do(req)
if err != nil {
logrus.Errorf("Failed request: %s", err)
return nil, err
}
defer resp.Body.Close()
rawResponse, err := httputil.DumpResponse(resp, true)
logrus.Debugf("Received raw response:\n%s", rawResponse)
if err != nil {
logrus.Errorf("Failed to dump response: %s", err)
}
response, err := ioutil.ReadAll(resp.Body)
if err != nil {
logrus.Errorf("Failed to read response: %s", response)
return nil, err
}
response, err = requestor.testInvalidResponse(resp, response)
if err != nil {
return nil, err
}
return response, nil
}