opentofu/vendor/github.com/cyberdelia/heroku-go/v3/transport.go
Paul Hinze 6fe2703665 Vendor all dependencies w/ Godep
* Remove `make updatedeps` from Travis build. We'll follow up with more
   specific plans around dependency updating in subsequent PRs.
 * Update all `make` targets to set `GO15VENDOREXPERIMENT=1` and to
   filter out `/vendor/` from `./...` where appropriate.
 * Temporarily remove `vet` from the `make test` target until we can
   figure out how to get it to not vet `vendor/`. (Initial
   experimentation failed to yield the proper incantation.)

Everything is pinned to current master, with the exception of:

 * Azure/azure-sdk-for-go which is pinned before the breaking change today
 * aws/aws-sdk-go which is pinned to the most recent tag

The documentation still needs to be updated, which we can do in a follow
up PR. The goal here is to unblock release.
2016-01-29 15:08:48 -06:00

153 lines
3.3 KiB
Go

package heroku
import (
"encoding/json"
"errors"
"fmt"
"log"
"net/http"
"net/http/httputil"
"os"
"strings"
"github.com/pborman/uuid"
)
var DefaultTransport = &Transport{}
var DefaultClient = &http.Client{
Transport: DefaultTransport,
}
type Transport struct {
// Username is the HTTP basic auth username for API calls made by this Client.
Username string
// Password is the HTTP basic auth password for API calls made by this Client.
Password string
// UserAgent to be provided in API requests. Set to DefaultUserAgent if not
// specified.
UserAgent string
// Debug mode can be used to dump the full request and response to stdout.
Debug bool
// AdditionalHeaders are extra headers to add to each HTTP request sent by
// this Client.
AdditionalHeaders http.Header
// Transport is the HTTP transport to use when making requests.
// It will default to http.DefaultTransport if nil.
Transport http.RoundTripper
}
// Forward CancelRequest to underlying Transport
func (t *Transport) CancelRequest(req *http.Request) {
type canceler interface {
CancelRequest(*http.Request)
}
tr, ok := t.Transport.(canceler)
if !ok {
log.Printf("heroku: Client Transport of type %T doesn't support CancelRequest; Timeout not supported\n", t.Transport)
return
}
tr.CancelRequest(req)
}
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
if t.Transport == nil {
t.Transport = http.DefaultTransport
}
// Making a copy of the Request so that
// we don't modify the Request we were given.
req = cloneRequest(req)
if t.UserAgent != "" {
req.Header.Set("User-Agent", t.UserAgent)
}
req.Header.Set("Accept", "application/vnd.heroku+json; version=3")
req.Header.Set("Request-Id", uuid.New())
req.SetBasicAuth(t.Username, t.Password)
for k, v := range t.AdditionalHeaders {
req.Header[k] = v
}
if t.Debug {
dump, err := httputil.DumpRequestOut(req, true)
if err != nil {
log.Println(err)
} else {
os.Stderr.Write(dump)
os.Stderr.Write([]byte{'\n', '\n'})
}
}
resp, err := t.Transport.RoundTrip(req)
if err != nil {
if resp != nil {
resp.Body.Close()
}
return nil, err
}
if t.Debug {
dump, err := httputil.DumpResponse(resp, true)
if err != nil {
log.Println(err)
} else {
os.Stderr.Write(dump)
os.Stderr.Write([]byte{'\n'})
}
}
if err = checkResponse(resp); err != nil {
if resp != nil {
resp.Body.Close()
}
return nil, err
}
return resp, nil
}
type Error struct {
error
ID string
URL string
}
func checkResponse(resp *http.Response) error {
if resp.StatusCode/100 != 2 { // 200, 201, 202, etc
var e struct {
Message string
ID string
URL string `json:"url"`
}
err := json.NewDecoder(resp.Body).Decode(&e)
if err != nil {
return fmt.Errorf("encountered an error : %s", resp.Status)
}
return Error{error: errors.New(e.Message), ID: e.ID, URL: e.URL}
}
if msg := resp.Header.Get("X-Heroku-Warning"); msg != "" {
log.Println(strings.TrimSpace(msg))
}
return nil
}
// cloneRequest returns a clone of the provided *http.Request.
func cloneRequest(req *http.Request) *http.Request {
// shallow copy of the struct
clone := new(http.Request)
*clone = *req
// deep copy of the Header
clone.Header = make(http.Header)
for k, s := range req.Header {
clone.Header[k] = s
}
return clone
}