Skip to content

Commit 5af5fa9

Browse files
authored
improvement: Parse full qualified redirect URI in error handler middleware. (#348)
Parse full qualified redirect URI in error handler middleware.
1 parent 42e3bd8 commit 5af5fa9

File tree

6 files changed

+41
-15
lines changed

6 files changed

+41
-15
lines changed

changelog/@unreleased/pr-348.v2.yml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type: improvement
2+
improvement:
3+
description: Parse full qualified redirect URI in error handler middleware.
4+
links:
5+
- https://github.com/palantir/conjure-go-runtime/pull/348

conjure-go-client/httpclient/client.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,11 @@ func (c *clientImpl) doOnce(
148148
return nil, werror.ErrorWithContextParams(ctx, "httpclient: use WithRequestMethod() to specify HTTP method")
149149
}
150150
reqURI := joinURIAndPath(baseURI, b.path)
151-
req, err := http.NewRequest(b.method, reqURI, nil)
151+
req, err := http.NewRequestWithContext(ctx, b.method, reqURI, nil)
152152
if err != nil {
153153
return nil, werror.WrapWithContextParams(ctx, err, "failed to build new HTTP request")
154154
}
155-
req = req.WithContext(ctx)
155+
156156
req.Header = b.headers
157157
if q := b.query.Encode(); q != "" {
158158
req.URL.RawQuery = q

conjure-go-client/httpclient/internal/request_retrier.go

-7
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,6 @@ func (r *RequestRetrier) getRetryFn(resp *http.Response, respErr error) func() b
127127
}
128128

129129
func (r *RequestRetrier) setURIAndResetBackoff(otherURI *url.URL) {
130-
// If the URI returned by relocation header is a relative path
131-
// We will resolve it with the current URI
132-
if !otherURI.IsAbs() {
133-
if currentURI := parseLocationURL(r.currentURI); currentURI != nil {
134-
otherURI = currentURI.ResolveReference(otherURI)
135-
}
136-
}
137130
nextURI := otherURI.String()
138131
r.relocatedURIs[otherURI.String()] = struct{}{}
139132
r.retrier.Reset()

conjure-go-client/httpclient/internal/retry.go

+10-4
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,10 @@ const (
6262
func isRetryOtherResponse(resp *http.Response, err error, errCode int) (bool, *url.URL) {
6363
if errCode == StatusCodeRetryOther || errCode == StatusCodeRetryTemporaryRedirect {
6464
locationStr, ok := LocationFromError(err)
65-
if ok {
66-
return true, parseLocationURL(locationStr)
65+
if !ok {
66+
return true, nil
6767
}
68+
return true, parseLocationURL(locationStr)
6869
}
6970

7071
if resp == nil {
@@ -74,8 +75,11 @@ func isRetryOtherResponse(resp *http.Response, err error, errCode int) (bool, *u
7475
resp.StatusCode != StatusCodeRetryTemporaryRedirect {
7576
return false, nil
7677
}
77-
locationStr := resp.Header.Get("Location")
78-
return true, parseLocationURL(locationStr)
78+
location, err := resp.Location()
79+
if err != nil {
80+
return true, nil
81+
}
82+
return true, location
7983
}
8084

8185
func parseLocationURL(locationStr string) *url.URL {
@@ -90,6 +94,8 @@ func parseLocationURL(locationStr string) *url.URL {
9094
return locationURL
9195
}
9296

97+
// isThrottleResponse returns true if the response a throttle response type. It
98+
// also returns a duration after which the failed URI can be retried
9399
func isThrottleResponse(resp *http.Response, errCode int) (bool, time.Duration) {
94100
if errCode == StatusCodeThrottle {
95101
return true, 0

conjure-go-client/httpclient/response_error_decoder_middleware.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,10 @@ func (d restErrorDecoder) DecodeError(resp *http.Response) error {
8181
unsafeParams := map[string]interface{}{}
8282
if resp.StatusCode >= http.StatusTemporaryRedirect &&
8383
resp.StatusCode < http.StatusBadRequest {
84-
unsafeParams["location"] = resp.Header.Get("Location")
84+
location, err := resp.Location()
85+
if err == nil {
86+
unsafeParams["location"] = location.String()
87+
}
8588
}
8689
wSafeParams := werror.SafeParams(safeParams)
8790
wUnsafeParams := werror.UnsafeParams(unsafeParams)

conjure-go-client/httpclient/response_error_decoder_middleware_test.go

+20-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func TestErrorDecoderMiddlewares(t *testing.T) {
6565
assert.True(t, ok)
6666
assert.Equal(t, 307, code)
6767
location, ok := httpclient.LocationFromError(err)
68-
assert.True(t, ok)
68+
assert.False(t, ok)
6969
assert.Equal(t, "", location)
7070
},
7171
},
@@ -79,6 +79,25 @@ func TestErrorDecoderMiddlewares(t *testing.T) {
7979
assert.NoError(t, err)
8080
},
8181
},
82+
{
83+
name: "307 with relative location",
84+
handler: func(w http.ResponseWriter, r *http.Request) {
85+
w.Header().Set("Location", "/newPath")
86+
w.WriteHeader(307)
87+
},
88+
verify: func(t *testing.T, u *url.URL, err error) {
89+
assert.EqualError(t, err, "httpclient request failed: 307 Temporary Redirect")
90+
code, ok := httpclient.StatusCodeFromError(err)
91+
assert.True(t, ok)
92+
assert.Equal(t, 307, code)
93+
location, ok := httpclient.LocationFromError(err)
94+
assert.True(t, ok)
95+
96+
// The redirect url is a path relative to original URI
97+
expected := u.ResolveReference(&url.URL{Path: "/newPath"})
98+
assert.Equal(t, expected.String(), location)
99+
},
100+
},
82101
{
83102
name: "404 DisableRestErrors",
84103
handler: http.NotFound,

0 commit comments

Comments
 (0)