rest: make auth preserving redirects an option

This commit is contained in:
Nick Craig-Wood 2023-06-25 14:58:25 +01:00
parent f6efaf2a63
commit 15ef3b90fa

View File

@ -151,6 +151,7 @@ type Opts struct {
NoRedirect bool // if this is set then the client won't follow redirects
// On Redirects, call this function - see the http.Client docs: https://pkg.go.dev/net/http#Client
CheckRedirect func(req *http.Request, via []*http.Request) error
AuthRedirect bool // if this is set then the client will redirect with Auth
}
// Copy creates a copy of the options
@ -216,6 +217,34 @@ func (api *Client) Do(req *http.Request) (*http.Response, error) {
return api.c.Do(req)
}
// ClientWithAuthRedirects makes a new http client which will re-apply Auth on redirects
func ClientWithAuthRedirects(c *http.Client) *http.Client {
clientCopy := *c
clientCopy.CheckRedirect = func(req *http.Request, via []*http.Request) error {
if len(via) >= 10 {
return errors.New("stopped after 10 redirects")
} else if len(via) == 0 {
return nil
}
prevReq := via[len(via)-1]
resp := req.Response
if resp == nil {
return nil
}
// Look at previous response to see if it was a redirect and preserve auth if so
switch resp.StatusCode {
case http.StatusMovedPermanently, http.StatusFound, http.StatusSeeOther, http.StatusTemporaryRedirect, http.StatusPermanentRedirect:
// Reapply Auth (if any) from previous request on redirect
auth := prevReq.Header.Get("Authorization")
if auth != "" {
req.Header.Add("Authorization", auth)
}
}
return nil
}
return &clientCopy
}
// Call makes the call and returns the http.Response
//
// if err == nil then resp.Body will need to be closed unless
@ -310,6 +339,8 @@ func (api *Client) Call(ctx context.Context, opts *Opts) (resp *http.Response, e
clientCopy := *api.c
clientCopy.CheckRedirect = opts.CheckRedirect
c = &clientCopy
} else if opts.AuthRedirect {
c = ClientWithAuthRedirects(api.c)
} else {
c = api.c
}