doRedirectsWithClient mirrors fasthttp's redirect loop for transports that do not expose DoRedirects (e.g. fasthttp.LBClient). The helper always issues the initial request, respects zero redirect limits, falls back to the default cap for negative values, and validates redirect targets before followi
(req *fasthttp.Request, resp *fasthttp.Response, maxRedirects int, client redirectClient)
| 297 | // initial request, respects zero redirect limits, falls back to the default cap |
| 298 | // for negative values, and validates redirect targets before following them. |
| 299 | func doRedirectsWithClient(req *fasthttp.Request, resp *fasthttp.Response, maxRedirects int, client redirectClient) error { |
| 300 | currentURL := req.URI().String() |
| 301 | redirects := 0 |
| 302 | singleRequestOnly := maxRedirects <= 0 |
| 303 | |
| 304 | if maxRedirects < 0 { |
| 305 | maxRedirects = defaultRedirectLimit |
| 306 | singleRequestOnly = false |
| 307 | } |
| 308 | |
| 309 | for { |
| 310 | req.SetRequestURI(currentURL) |
| 311 | |
| 312 | if err := client.Do(req, resp); err != nil { |
| 313 | return err |
| 314 | } |
| 315 | |
| 316 | statusCode := resp.Header.StatusCode() |
| 317 | if !fasthttp.StatusCodeIsRedirect(statusCode) { |
| 318 | return nil |
| 319 | } |
| 320 | |
| 321 | if singleRequestOnly { |
| 322 | return nil |
| 323 | } |
| 324 | |
| 325 | redirects++ |
| 326 | if redirects > maxRedirects { |
| 327 | return fasthttp.ErrTooManyRedirects |
| 328 | } |
| 329 | |
| 330 | location := resp.Header.Peek("Location") |
| 331 | if len(location) == 0 { |
| 332 | return fasthttp.ErrMissingLocation |
| 333 | } |
| 334 | |
| 335 | nextURL, err := composeRedirectURL(currentURL, location, req.DisableRedirectPathNormalizing) |
| 336 | if err != nil { |
| 337 | return err |
| 338 | } |
| 339 | currentURL = nextURL |
| 340 | |
| 341 | if req.Header.IsPost() && (statusCode == fasthttp.StatusMovedPermanently || statusCode == fasthttp.StatusFound || statusCode == fasthttp.StatusSeeOther) { |
| 342 | req.Header.SetMethod(fasthttp.MethodGet) |
| 343 | req.SetBody(nil) |
| 344 | req.Header.Del(fasthttp.HeaderContentType) |
| 345 | req.Header.Del(fasthttp.HeaderContentLength) |
| 346 | } |
| 347 | } |
| 348 | } |
| 349 | |
| 350 | // composeRedirectURL resolves a redirect target relative to the current request |
| 351 | // URL while rejecting suspicious payloads (e.g. control characters) and |