{"record":{"id":"e227d5bb5a9054a2","repo":"gofiber/fiber","slug":"w-w","errorCode":null,"errorMessage":"%w: %w","messagePattern":"%w: %w","errorType":"exception","errorClass":"ErrorInvalidURI","httpStatus":null,"severity":"error","filePath":"client/transport.go","lineNumber":491,"sourceCode":"}\n\n// composeRedirectURL resolves a redirect target relative to the current request\n// URL while rejecting suspicious payloads (e.g. control characters) and\n// restricting schemes to HTTP/S so caller-provided Location headers cannot\n// trigger arbitrary transports. Redirects from HTTPS to plaintext HTTP are\n// rejected to prevent credentials from leaking after a TLS handshake.\n//\n// It returns the resolved URL along with its host, which the caller compares\n// against the previous hop to decide whether origin-scoped credentials still\n// apply.\n// parsesAsURI reports whether fasthttp reads full as a URI at all, returning the\n// reason it does not. Only Parse surfaces that; Update and UpdateBytes discard it.\nfunc parsesAsURI(full []byte) error {\n\tcheck := fasthttp.AcquireURI()\n\tdefer fasthttp.ReleaseURI(check)\n\n\tif err := check.Parse(nil, full); err != nil {\n\t\treturn fmt.Errorf(\"%w: %w\", fasthttp.ErrorInvalidURI, err)\n\t}\n\treturn nil\n}\n\nfunc composeRedirectURL(base string, location []byte, disablePathNormalizing bool) (redirectURL, host string, err error) { //nolint:nonamedreturns // names document the two string results\n\tfor _, b := range location {\n\t\tif b < 0x20 || b == 0x7f {\n\t\t\treturn \"\", \"\", fasthttp.ErrorInvalidURI\n\t\t}\n\t}\n\n\turi := fasthttp.AcquireURI()\n\tdefer fasthttp.ReleaseURI(uri)\n\n\turi.Update(base)\n\twasHTTPS := utils.EqualFold(uri.Scheme(), httpsScheme)\n\turi.UpdateBytes(location)\n\turi.DisablePathNormalizing = disablePathNormalizing","sourceCodeStart":473,"sourceCodeEnd":509,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/client/transport.go#L473-L509","documentation":"When following a redirect, composeRedirectURL re-parses the resolved URI with fasthttp and, if Parse rejects it, returns this dual-wrapped error: fasthttp.ErrorInvalidURI wrapping the concrete parse cause. It signals that the redirect's Location header (combined with the base URL) does not form a valid URI — e.g. a bad port, illegal host bytes, or scheme/host inconsistency that fasthttp's UpdateBytes silently tolerated but Parse caught.","triggerScenarios":"A server returns a Location header with an invalid port (http://host:abc/x), malformed IPv6 literal, control bytes that survived the earlier filter, or a scheme that fasthttp rejects. The earlier 0x20/0x7f filter and scheme checks (http/https only, HTTPS→HTTP downgrade) run first; reaching this line means a subtler URI defect.","commonSituations":"Misconfigured upstream returning a broken Location; a reverse proxy rewriting Location incorrectly; an attacker-controlled redirect crafted to stress URI parsers; fasthttp version differences in strictness.","solutions":["Disable redirect following (maxRedirects = 0) if you do not trust upstream Location headers, and resolve redirects yourself.","Validate the Location header with net/url.Parse before following if you implement a custom redirect policy.","Log the wrapped cause — it specifies the exact parse failure (port, host, scheme)."],"exampleFix":"// before\nc.SetRedirectPolicy(client.RedirectPolicy{MaxRedirects: 10})\n\n// after (opt out and handle manually)\nc.SetRedirectPolicy(client.RedirectPolicy{MaxRedirects: 0})\nloc := resp.RawResponse.Header.Peek(\"Location\")\nu, err := url.Parse(string(loc))\nif err != nil { return fmt.Errorf(\"bad redirect: %w\", err) }","handlingStrategy":"validation","validationCode":"loc := resp.RawResponse.Header.Peek(\"Location\")\nif _, err := url.Parse(string(loc)); err != nil {\n    return fmt.Errorf(\"upstream returned bad redirect: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if maxRedirects == 0 || err != nil && errors.Is(err, fasthttp.ErrorInvalidURI) {\n    // do not follow; surface to caller\n}","preventionTips":["Disable redirect following when you do not trust upstream Location headers.","Validate Location with net/url.Parse before following if you implement a custom redirect policy.","Reject HTTPS→HTTP downgrades and non-http(s) schemes explicitly in your policy."],"tags":["client","redirect","url-parsing","transport","security"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}