123 lines
3.2 KiB
Go
123 lines
3.2 KiB
Go
package requests
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"github.com/Sirupsen/logrus"
|
|
request_errors "github.com/edeckers/auroradnsclient/requests/errors"
|
|
"github.com/edeckers/auroradnsclient/tokens"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/http/httputil"
|
|
"time"
|
|
)
|
|
|
|
// 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
|
|
}
|