From b4fe1dffb478c86f72932e364c61419301ba897c Mon Sep 17 00:00:00 2001 From: Dwi Siswanto Date: Thu, 12 Dec 2024 11:39:36 +0700 Subject: [PATCH] fix(httpclientpool): rebuild malformed Location URL Signed-off-by: Dwi Siswanto --- .../http/httpclientpool/clientpool.go | 28 ++++++++++++++++++- pkg/protocols/http/httpclientpool/errors.go | 7 +++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 pkg/protocols/http/httpclientpool/errors.go diff --git a/pkg/protocols/http/httpclientpool/clientpool.go b/pkg/protocols/http/httpclientpool/clientpool.go index 94ed61ff3f..7f9eeed140 100644 --- a/pkg/protocols/http/httpclientpool/clientpool.go +++ b/pkg/protocols/http/httpclientpool/clientpool.go @@ -3,6 +3,7 @@ package httpclientpool import ( "context" "crypto/tls" + "fmt" "net" "net/http" "net/http/cookiejar" @@ -25,6 +26,7 @@ import ( "github.com/projectdiscovery/rawhttp" "github.com/projectdiscovery/retryablehttp-go" mapsutil "github.com/projectdiscovery/utils/maps" + urlutil "github.com/projectdiscovery/utils/url" ) var ( @@ -377,7 +379,7 @@ func makeCheckRedirectFunc(redirectType RedirectFlow, maxRedirects int) checkRed } } -func checkMaxRedirects(_ *http.Request, via []*http.Request, maxRedirects int) error { +func checkMaxRedirects(req *http.Request, via []*http.Request, maxRedirects int) error { if maxRedirects == 0 { if len(via) > defaultMaxRedirects { return http.ErrUseLastResponse @@ -388,5 +390,29 @@ func checkMaxRedirects(_ *http.Request, via []*http.Request, maxRedirects int) e if len(via) > maxRedirects { return http.ErrUseLastResponse } + + // NOTE(dwisiswant0): rebuild request URL. See #5900. + if u := req.URL.String(); !isURLEncoded(u) { + parsed, err := urlutil.Parse(u) + if err != nil { + return fmt.Errorf("%w: %w", ErrRebuildURL, err) + } + + req.URL = parsed.URL + } + return nil } + +// isURLEncoded is an helper function to check if the URL is already encoded +// +// NOTE(dwisiswant0): shall we move this under `projectdiscovery/utils/urlutil`? +func isURLEncoded(s string) bool { + decoded, err := url.QueryUnescape(s) + if err != nil { + // If decoding fails, it may indicate a malformed URL/invalid encoding. + return false + } + + return decoded != s +} diff --git a/pkg/protocols/http/httpclientpool/errors.go b/pkg/protocols/http/httpclientpool/errors.go new file mode 100644 index 0000000000..e5c915f93e --- /dev/null +++ b/pkg/protocols/http/httpclientpool/errors.go @@ -0,0 +1,7 @@ +package httpclientpool + +import "errors" + +var ( + ErrRebuildURL = errors.New("could not rebuild request URL") +)