Skip to content

Commit 11da9a3

Browse files
committed
Refactor doIPRanges as DoJSON
I added response header hook support to IPRanges. Previously, it was not possible to encounter an HTTP status error on IPRanges because this condition could never be met: `if resp.StatusCode < 200 && resp.StatusCode >= 400 {`
1 parent e0cfb6c commit 11da9a3

File tree

4 files changed

+33
-15
lines changed

4 files changed

+33
-15
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
## Enhancements
66
* Adds `RunPreApplyRunning` and `RunQueuingApply` run statuses by @uk1288 [#712](https://github.com/hashicorp/go-tfe/pull/712)
77
* Adds BETA method `Upload` method to `StateVersions` and support for pending state versions by @brandonc [#717](https://github.com/hashicorp/go-tfe/pull/717)
8+
* Added ContextWithResponseHeaderHook support to `IPRanges` by @brandonc [#717](https://github.com/hashicorp/go-tfe/pull/717)
89

910
## Bug Fixes
1011
* AgentPool `Update` is not able to remove all allowed workspaces from an agent pool. That operation is now handled by a separate `UpdateAllowedWorkspaces` method using `AgentPoolAllowedWorkspacesUpdateOptions` by @hs26gill [#701](https://github.com/hashicorp/go-tfe/pull/701)

ip_ranges.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func (i *ipRanges) Read(ctx context.Context, modifiedSince string) (*IPRange, er
5050
}
5151

5252
ir := &IPRange{}
53-
err = req.doIPRanges(ctx, ir)
53+
err = req.DoJSON(ctx, ir)
5454
if err != nil {
5555
return nil, err
5656
}

request.go

+24-10
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ func (r ClientRequest) Do(ctx context.Context, model interface{}) error {
7878
return unmarshalResponse(resp.Body, model)
7979
}
8080

81-
// doIPRanges is similar to Do except that The IP ranges API is not returning jsonapi
82-
// like every other endpoint which means we need to handle it differently.
83-
func (r *ClientRequest) doIPRanges(ctx context.Context, ir *IPRange) error {
81+
// DoJSON is similar to Do except that it should be used when a plain JSON response is expected
82+
// as opposed to json-api.
83+
func (r *ClientRequest) DoJSON(ctx context.Context, model any) error {
8484
// Wait will block until the limiter can obtain a new token
8585
// or returns an error if the given context is canceled.
8686
if r.limiter != nil {
@@ -92,8 +92,18 @@ func (r *ClientRequest) doIPRanges(ctx context.Context, ir *IPRange) error {
9292
// Add the context to the request.
9393
contextReq := r.retryableRequest.WithContext(ctx)
9494

95+
// If the caller provided a response header hook then we'll call it
96+
// once we have a response.
97+
respHeaderHook := contextResponseHeaderHook(ctx)
98+
9599
// Execute the request and check the response.
96100
resp, err := r.http.Do(contextReq)
101+
if resp != nil {
102+
// We call the callback whenever there's any sort of response,
103+
// even if it's returned in conjunction with an error.
104+
respHeaderHook(resp.StatusCode, resp.Header)
105+
}
106+
defer resp.Body.Close()
97107
if err != nil {
98108
// If we got an error, and the context has been canceled,
99109
// the context's error is probably more useful.
@@ -104,17 +114,21 @@ func (r *ClientRequest) doIPRanges(ctx context.Context, ir *IPRange) error {
104114
return err
105115
}
106116
}
107-
defer resp.Body.Close()
108117

109-
if resp.StatusCode < 200 && resp.StatusCode >= 400 {
110-
return fmt.Errorf("error HTTP response while retrieving IP ranges: %d", resp.StatusCode)
111-
} else if resp.StatusCode == 304 {
118+
if resp.StatusCode < 200 || resp.StatusCode >= 400 {
119+
return fmt.Errorf("error HTTP response: %d", resp.StatusCode)
120+
}
121+
122+
// Return here if decoding the response isn't needed.
123+
if model == nil {
112124
return nil
113125
}
114126

115-
err = json.NewDecoder(resp.Body).Decode(ir)
116-
if err != nil {
127+
// If v implements io.Writer, write the raw response body.
128+
if w, ok := model.(io.Writer); ok {
129+
_, err := io.Copy(w, resp.Body)
117130
return err
118131
}
119-
return nil
132+
133+
return json.NewDecoder(resp.Body).Decode(model)
120134
}

tfe.go

+7-4
Original file line numberDiff line numberDiff line change
@@ -198,14 +198,17 @@ type Meta struct {
198198
IPRanges IPRanges
199199
}
200200

201-
func (c *Client) doForeignPUTRequest(ctx context.Context, foreignUrl string, data io.Reader) error {
202-
u, err := url.Parse(foreignUrl)
201+
// doForeignPUTRequest performs a PUT request using the specific data body. The Content-Type
202+
// header is set to application/octet-stream but no Authentication header is sent. No response
203+
// body is decoded.
204+
func (c *Client) doForeignPUTRequest(ctx context.Context, foreignURL string, data io.Reader) error {
205+
u, err := url.Parse(foreignURL)
203206
if err != nil {
204207
return fmt.Errorf("specified URL was not valid: %w", err)
205208
}
206209

207210
reqHeaders := make(http.Header)
208-
reqHeaders.Set("Accept", "application/json")
211+
reqHeaders.Set("Accept", "application/json, */*")
209212
reqHeaders.Set("Content-Type", "application/octet-stream")
210213

211214
req, err := retryablehttp.NewRequest("PUT", u.String(), data)
@@ -229,7 +232,7 @@ func (c *Client) doForeignPUTRequest(ctx context.Context, foreignUrl string, dat
229232
Header: req.Header,
230233
}
231234

232-
return request.Do(ctx, nil)
235+
return request.DoJSON(ctx, nil)
233236
}
234237

235238
func (c *Client) NewRequest(method, path string, reqAttr any) (*ClientRequest, error) {

0 commit comments

Comments
 (0)