diff --git a/compat/lazyload-curl.c b/compat/lazyload-curl.c index a6a3f7e3a7aeaa..c361eab85cd1fb 100644 --- a/compat/lazyload-curl.c +++ b/compat/lazyload-curl.c @@ -175,6 +175,20 @@ static curl_easy_setopt_pointer_type curl_easy_setopt_pointer_func; typedef CURLcode (*curl_easy_setopt_off_t_type)(CURL *curl, CURLoption opt, curl_off_t value); static curl_easy_setopt_off_t_type curl_easy_setopt_off_t_func; +typedef CURLU *(*curl_url_type)(void); +static curl_url_type curl_url_func; + +typedef void (*curl_url_cleanup_type)(CURLU *u); +static curl_url_cleanup_type curl_url_cleanup_func; + +typedef CURLUcode (*curl_url_get_type)(const CURLU *u, CURLUPart what, + char **part, unsigned int flags); +static curl_url_get_type curl_url_get_func; + +typedef CURLUcode (*curl_url_set_type)(CURLU *u, CURLUPart what, + const char *part, unsigned int flags); +static curl_url_set_type curl_url_set_func; + static char ssl_backend[64]; static void lazy_load_curl(void) @@ -231,6 +245,11 @@ static void lazy_load_curl(void) curl_easy_setopt_long_func = (curl_easy_setopt_long_type)curl_easy_setopt_func; curl_easy_setopt_pointer_func = (curl_easy_setopt_pointer_type)curl_easy_setopt_func; curl_easy_setopt_off_t_func = (curl_easy_setopt_off_t_type)curl_easy_setopt_func; + + curl_url_func = (curl_url_type)load_function(libcurl, "curl_url"); + curl_url_cleanup_func = (curl_url_cleanup_type)load_function(libcurl, "curl_url_cleanup"); + curl_url_get_func = (curl_url_get_type)load_function(libcurl, "curl_url_get"); + curl_url_set_func = (curl_url_set_type)load_function(libcurl, "curl_url_set"); } struct curl_version_info_data *curl_version_info(CURLversion version) @@ -426,3 +445,25 @@ CURLcode curl_easy_setopt(CURL *curl, CURLoption opt, ...) va_end(ap); return res; } + +CURLU *curl_url(void) +{ + return curl_url_func(); +} + +void curl_url_cleanup(CURLU *u) +{ + curl_url_cleanup_func(u); +} + +CURLUcode curl_url_get(const CURLU *u, CURLUPart what, + char **part, unsigned int flags) +{ + return curl_url_get_func(u, what, part, flags); +} + +CURLUcode curl_url_set(CURLU *u, CURLUPart what, + const char *part, unsigned int flags) +{ + return curl_url_set_func(u, what, part, flags); +} diff --git a/git-curl-compat.h b/git-curl-compat.h index 032aaf7126c977..25678b5dbd2c80 100644 --- a/git-curl-compat.h +++ b/git-curl-compat.h @@ -28,6 +28,13 @@ * introduced, oldest first, in the official version of cURL library. */ +/** + * curl_url() interface added in 7.62.0 (October 2018) + */ +#if LIBCURL_VERSION_NUM >= 0x073e00 +#define GIT_CURL_HAVE_CURL_URL +#endif + /** * Versions before curl 7.66.0 (September 2019) required manually setting the * transfer-encoding for a streaming POST; after that this is handled diff --git a/http.c b/http.c index c8fcfd7693e897..4af3c29c769559 100644 --- a/http.c +++ b/http.c @@ -2315,6 +2315,45 @@ static int http_request(const char *url, return ret; } +#ifndef GIT_CURL_HAVE_CURL_URL +#define strip_url_credential(in) NULL +#else +static char *strip_url_credential(const char *in) +{ + char *ret = NULL; + CURLU *url; + + url = curl_url(); + if (!url) + goto out; + + if (curl_url_set(url, CURLUPART_URL, in, 0)) + goto out; + + curl_url_set(url, CURLUPART_USER, NULL, 0); + curl_url_set(url, CURLUPART_PASSWORD, NULL, 0); + curl_url_get(url, CURLUPART_URL, &ret, 0); + +out: + curl_url_cleanup(url); + return ret; +} +#endif + +static int match_effective_url(const char *asked, const char *got) +{ + char *stripped; + int ret; + + if (!strcmp(asked, got)) + return 1; + + stripped = strip_url_credential(asked); + ret = stripped && !strcmp(stripped, got); + curl_free(stripped); + return ret; +} + /* * Update the "base" url to a more appropriate value, as deduced by * redirects seen when requesting a URL starting with "url". @@ -2347,7 +2386,7 @@ static int update_url_from_redirect(struct strbuf *base, const char *tail; size_t new_len; - if (!strcmp(asked, got->buf)) + if (match_effective_url(asked, got->buf)) return 0; if (!skip_prefix(asked, base->buf, &tail))