Merge branch 'aw/validate-proxy-url-scheme'

Misspelt proxy URL (e.g., httt://...) did not trigger any warning
or failure, which has been corrected.

* aw/validate-proxy-url-scheme:
  http: reject unsupported proxy URL schemes
main
Junio C Hamano 2026-05-21 12:06:48 +09:00
commit 490efd7cb4
2 changed files with 74 additions and 25 deletions

93
http.c
View File

@ -761,6 +761,69 @@ static int has_proxy_cert_password(void)
return 1;
}

static const struct socks_proxy_type {
const char *name;
long curlsym;
} socks_proxy_types[] = {
{ "socks", CURLPROXY_SOCKS4 },
{ "socks4", CURLPROXY_SOCKS4 },
{ "socks4a", CURLPROXY_SOCKS4A },
{ "socks5", CURLPROXY_SOCKS5 },
{ "socks5h", CURLPROXY_SOCKS5_HOSTNAME },
};

static const struct socks_proxy_type *find_socks_proxy_type(const char *protocol)
{
int i;

if (!protocol)
return NULL;

for (i = 0; i < ARRAY_SIZE(socks_proxy_types); i++) {
if (!strcmp(socks_proxy_types[i].name, protocol))
return &socks_proxy_types[i];
}

return NULL;
}

static int is_socks_proxy_protocol(const char *protocol)
{
return !!find_socks_proxy_type(protocol);
}

static int set_curl_proxy_type(CURL *result, const char *protocol)
{
const struct socks_proxy_type *socks_proxy_type;

if (!protocol || !strcmp(protocol, "http"))
return 0;

socks_proxy_type = find_socks_proxy_type(protocol);
if (socks_proxy_type) {
curl_easy_setopt(result, CURLOPT_PROXYTYPE, socks_proxy_type->curlsym);
return 0;
}

if (!strcmp(protocol, "https")) {
curl_easy_setopt(result, CURLOPT_PROXYTYPE, (long)CURLPROXY_HTTPS);

if (http_proxy_ssl_cert)
curl_easy_setopt(result, CURLOPT_PROXY_SSLCERT,
http_proxy_ssl_cert);

if (http_proxy_ssl_key)
curl_easy_setopt(result, CURLOPT_PROXY_SSLKEY,
http_proxy_ssl_key);

if (has_proxy_cert_password())
curl_easy_setopt(result, CURLOPT_PROXY_KEYPASSWD,
proxy_cert_auth.password);
}

return -1;
}

/* Return 1 if redactions have been made, 0 otherwise. */
static int redact_sensitive_header(struct strbuf *header, size_t offset)
{
@ -1231,30 +1294,6 @@ static CURL *get_curl_handle(void)
} else if (curl_http_proxy) {
struct strbuf proxy = STRBUF_INIT;

if (starts_with(curl_http_proxy, "socks5h"))
curl_easy_setopt(result,
CURLOPT_PROXYTYPE, (long)CURLPROXY_SOCKS5_HOSTNAME);
else if (starts_with(curl_http_proxy, "socks5"))
curl_easy_setopt(result,
CURLOPT_PROXYTYPE, (long)CURLPROXY_SOCKS5);
else if (starts_with(curl_http_proxy, "socks4a"))
curl_easy_setopt(result,
CURLOPT_PROXYTYPE, (long)CURLPROXY_SOCKS4A);
else if (starts_with(curl_http_proxy, "socks"))
curl_easy_setopt(result,
CURLOPT_PROXYTYPE, (long)CURLPROXY_SOCKS4);
else if (starts_with(curl_http_proxy, "https")) {
curl_easy_setopt(result, CURLOPT_PROXYTYPE, (long)CURLPROXY_HTTPS);

if (http_proxy_ssl_cert)
curl_easy_setopt(result, CURLOPT_PROXY_SSLCERT, http_proxy_ssl_cert);

if (http_proxy_ssl_key)
curl_easy_setopt(result, CURLOPT_PROXY_SSLKEY, http_proxy_ssl_key);

if (has_proxy_cert_password())
curl_easy_setopt(result, CURLOPT_PROXY_KEYPASSWD, proxy_cert_auth.password);
}
if (strstr(curl_http_proxy, "://"))
credential_from_url(&proxy_auth, curl_http_proxy);
else {
@ -1264,6 +1303,10 @@ static CURL *get_curl_handle(void)
strbuf_release(&url);
}

if (set_curl_proxy_type(result, proxy_auth.protocol) < 0)
die("Invalid proxy URL '%s': unsupported proxy scheme '%s'",
curl_http_proxy, proxy_auth.protocol);

if (!proxy_auth.host)
die("Invalid proxy URL '%s'", curl_http_proxy);

@ -1274,7 +1317,7 @@ static CURL *get_curl_handle(void)
if (ver->version_num < 0x075400)
die("libcurl 7.84 or later is required to support paths in proxy URLs");

if (!starts_with(proxy_auth.protocol, "socks"))
if (!is_socks_proxy_protocol(proxy_auth.protocol))
die("Invalid proxy URL '%s': only SOCKS proxies support paths",
curl_http_proxy);


View File

@ -102,4 +102,10 @@ test_expect_success 'Unix socket requires localhost' - <<\EOT
}
EOT

test_expect_success 'unknown proxy scheme is rejected' '
test_must_fail git clone -c http.proxy=htpp://127.0.0.1 \
https://example.com/repo.git 2>err &&
test_grep "unsupported proxy scheme '\''htpp'\''" err
'

test_done