From f2a67d3a210daeac0d6a173ea6adb10c2c5859af Mon Sep 17 00:00:00 2001 From: "Jeevanandam M." Date: Mon, 30 Dec 2024 20:30:14 -0800 Subject: [PATCH] feat: add redirect history feature #295 (#933) --- client_test.go | 11 +++++++++-- redirect.go | 6 ++++++ request_test.go | 11 ++++++++++- response.go | 20 ++++++++++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/client_test.go b/client_test.go index 94e4c9d9..db81f4c3 100644 --- a/client_test.go +++ b/client_test.go @@ -116,7 +116,7 @@ func TestClientRedirectPolicy(t *testing.T) { defer ts.Close() c := dcnl().SetRedirectPolicy(FlexibleRedirectPolicy(20), DomainCheckRedirectPolicy("127.0.0.1")) - _, err := c.R(). + res, err := c.R(). SetHeader("Name1", "Value1"). SetHeader("Name2", "Value2"). SetHeader("Name3", "Value3"). @@ -124,8 +124,15 @@ func TestClientRedirectPolicy(t *testing.T) { assertEqual(t, true, err.Error() == "Get \"/redirect-21\": resty: stopped after 20 redirects") + redirects := res.RedirectHistory() + assertEqual(t, 20, len(redirects)) + + finalReq := redirects[0] + assertEqual(t, 307, finalReq.StatusCode) + assertEqual(t, ts.URL+"/redirect-20", finalReq.URL) + c.SetRedirectPolicy(NoRedirectPolicy()) - res, err := c.R().Get(ts.URL + "/redirect-1") + res, err = c.R().Get(ts.URL + "/redirect-1") assertNil(t, err) assertEqual(t, http.StatusTemporaryRedirect, res.StatusCode()) assertEqual(t, `Temporary Redirect.`, res.String()) diff --git a/redirect.go b/redirect.go index 32ab4792..d78ce80d 100644 --- a/redirect.go +++ b/redirect.go @@ -27,6 +27,12 @@ type ( // functions as [RedirectPolicy]. If `f` is a function with the appropriate // signature, RedirectPolicyFunc(f) is a RedirectPolicy object that calls `f`. RedirectPolicyFunc func(*http.Request, []*http.Request) error + + // RedirectInfo struct is used to capture the URL and status code for the redirect history + RedirectInfo struct { + URL string + StatusCode int + } ) // Apply calls f(req, via). diff --git a/request_test.go b/request_test.go index 091c446d..f046466f 100644 --- a/request_test.go +++ b/request_test.go @@ -911,7 +911,13 @@ func TestHTTPAutoRedirectUpTo10(t *testing.T) { ts := createRedirectServer(t) defer ts.Close() - _, err := dcnl().R().Get(ts.URL + "/redirect-1") + res, err := dcnl().R().Get(ts.URL + "/redirect-1") + redirects := res.RedirectHistory() + assertEqual(t, 10, len(redirects)) + + finalReq := redirects[0] + assertEqual(t, 307, finalReq.StatusCode) + assertEqual(t, ts.URL+"/redirect-10", finalReq.URL) assertEqual(t, true, (err.Error() == "Get /redirect-11: stopped after 10 redirects" || err.Error() == "Get \"/redirect-11\": stopped after 10 redirects")) @@ -2338,6 +2344,9 @@ func TestRequestSettingsCoverage(t *testing.T) { result := jsonIndent(invalidJsonBytes) assertEqual(t, string(invalidJsonBytes), string(result)) + res := &Response{} + assertNil(t, res.RedirectHistory()) + defer func() { if rec := recover(); rec != nil { if err, ok := rec.(error); ok { diff --git a/response.go b/response.go index 691f4e91..3299f797 100644 --- a/response.go +++ b/response.go @@ -153,6 +153,26 @@ func (r *Response) IsError() bool { return r.StatusCode() > 399 } +// RedirectHistory method returns a redirect history slice with the URL and status code +func (r *Response) RedirectHistory() []*RedirectInfo { + if r.RawResponse == nil { + return nil + } + + redirects := make([]*RedirectInfo, 0) + res := r.RawResponse + for res != nil { + req := res.Request + redirects = append(redirects, &RedirectInfo{ + StatusCode: res.StatusCode, + URL: req.URL.String(), + }) + res = req.Response + } + + return redirects +} + func (r *Response) setReceivedAt() { r.receivedAt = time.Now() if r.Request.trace != nil {