Skip to content

Commit

Permalink
Don't set "Content-Type" header on GET requests
Browse files Browse the repository at this point in the history
Updates the `NewRequest` logic to prevent the `Content-Type` header from
being set on GET, HEAD, and OPTIONS requests. Also prevents a body from
being set to anything other than nil for those requests.

This also adds a new client initialization option that allows users to
define arbitrary key value pairs that are set as HTTP headers on each
request. The intent is that people can use these if they need to set
extra headers when using godo behind some kind of proxy.
  • Loading branch information
bentranter committed Dec 1, 2020
1 parent 4e6f6e6 commit 8c2ad8c
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 11 deletions.
49 changes: 40 additions & 9 deletions godo.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ type Client struct {

// Optional function called after every successful request made to the DO APIs
onRequestCompleted RequestCompletionCallback

// Optional extra HTTP headers to set on every request to the API.
headers map[string]string
}

// RequestCompletionCallback defines the type of the request callback function
Expand Down Expand Up @@ -215,6 +218,8 @@ func NewClient(httpClient *http.Client) *Client {
c.VPCs = &VPCsServiceOp{client: c}
c.OneClick = &OneClickServiceOp{client: c}

c.headers = make(map[string]string)

return c
}

Expand Down Expand Up @@ -254,6 +259,17 @@ func SetUserAgent(ua string) ClientOpt {
}
}

// SetRequestHeaders sets optional HTTP headers on the client that are
// sent on each HTTP request.
func SetRequestHeaders(headers map[string]string) ClientOpt {
return func(c *Client) error {
for k, v := range headers {
c.headers[k] = v
}
return nil
}
}

// NewRequest creates an API request. A relative URL can be provided in urlStr, which will be resolved to the
// BaseURL of the Client. Relative URLS should always be specified without a preceding slash. If specified, the
// value pointed to by body is JSON encoded and included in as the request body.
Expand All @@ -263,22 +279,37 @@ func (c *Client) NewRequest(ctx context.Context, method, urlStr string, body int
return nil, err
}

buf := new(bytes.Buffer)
if body != nil {
err = json.NewEncoder(buf).Encode(body)
var req *http.Request
switch method {
case http.MethodGet, http.MethodHead, http.MethodOptions:
req, err = http.NewRequest(method, u.String(), nil)
if err != nil {
return nil, err
}

default:
buf := new(bytes.Buffer)
if body != nil {
err = json.NewEncoder(buf).Encode(body)
if err != nil {
return nil, err
}
}

req, err = http.NewRequest(method, u.String(), buf)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", mediaType)
}

req, err := http.NewRequest(method, u.String(), buf)
if err != nil {
return nil, err
for k, v := range c.headers {
req.Header.Add(k, v)
}

req.Header.Add("Content-Type", mediaType)
req.Header.Add("Accept", mediaType)
req.Header.Add("User-Agent", c.UserAgent)
req.Header.Set("Accept", mediaType)
req.Header.Set("User-Agent", c.UserAgent)

return req, nil
}

Expand Down
27 changes: 25 additions & 2 deletions godo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func TestNewRequest(t *testing.T) {
`{"name":"l","region":"","size":"","image":0,`+
`"ssh_keys":null,"backups":false,"ipv6":false,`+
`"private_networking":false,"monitoring":false,"tags":null}`+"\n"
req, _ := c.NewRequest(ctx, http.MethodGet, inURL, inBody)
req, _ := c.NewRequest(ctx, http.MethodPost, inURL, inBody)

// test relative URL was expanded
if req.URL.String() != outURL {
Expand All @@ -167,6 +167,29 @@ func TestNewRequest(t *testing.T) {
}
}

func TestNewRequest_get(t *testing.T) {
c := NewClient(nil)

inURL, outURL := "/foo", defaultBaseURL+"foo"
req, _ := c.NewRequest(ctx, http.MethodGet, inURL, nil)

// test relative URL was expanded
if req.URL.String() != outURL {
t.Errorf("NewRequest(%v) URL = %v, expected %v", inURL, req.URL, outURL)
}

// test the content-type header is not set
if contentType := req.Header.Get("Content-Type"); contentType != "" {
t.Errorf("NewRequest() Content-Type = %v, expected empty string", contentType)
}

// test default user-agent is attached to the request
userAgent := req.Header.Get("User-Agent")
if c.UserAgent != userAgent {
t.Errorf("NewRequest() User-Agent = %v, expected %v", userAgent, c.UserAgent)
}
}

func TestNewRequest_withUserData(t *testing.T) {
c := NewClient(nil)

Expand All @@ -175,7 +198,7 @@ func TestNewRequest_withUserData(t *testing.T) {
`{"name":"l","region":"","size":"","image":0,`+
`"ssh_keys":null,"backups":false,"ipv6":false,`+
`"private_networking":false,"monitoring":false,"user_data":"u","tags":null}`+"\n"
req, _ := c.NewRequest(ctx, http.MethodGet, inURL, inBody)
req, _ := c.NewRequest(ctx, http.MethodPost, inURL, inBody)

// test relative URL was expanded
if req.URL.String() != outURL {
Expand Down

0 comments on commit 8c2ad8c

Please sign in to comment.