From 18475e662cb3655dc2c5ac962ac81a233ca86faf Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Jun 2026 11:36:23 +0200 Subject: [PATCH] urlpieces: remove members that live in peers/creds Remove members of `struct urlpieces` that now live in peers/creds. Change all remaining uses of those urlpieces. When comparing schemes, use the protocol constants. Closes #22171 --- lib/http.c | 4 ++-- lib/http_proxy.c | 4 ++-- lib/ldap.c | 3 ++- lib/openldap.c | 22 +++++++++++++++------- lib/peer.c | 30 +++++++++++------------------- lib/peer.h | 2 -- lib/url.c | 26 ++++++++++++-------------- lib/urlapi-int.h | 2 ++ lib/urlapi.c | 17 +++++++++++++++++ lib/urldata.h | 5 ----- lib/vssh/libssh.c | 4 ++-- 11 files changed, 65 insertions(+), 54 deletions(-) diff --git a/lib/http.c b/lib/http.c index a0aee51c78..072b1ed3b4 100644 --- a/lib/http.c +++ b/lib/http.c @@ -2115,7 +2115,7 @@ static CURLcode http_target(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } - if(curl_strequal("http", data->state.up.scheme)) { + if(data->state.origin->scheme == &Curl_scheme_http) { /* when getting HTTP, we do not want the userinfo the URL */ uc = curl_url_set(h, CURLUPART_USER, NULL, 0); if(uc) { @@ -2157,7 +2157,7 @@ static CURLcode http_target(struct Curl_easy *data, if(result) return result; - if(curl_strequal("ftp", data->state.up.scheme) && + if((data->state.origin->scheme == &Curl_scheme_ftp) && data->set.proxy_transfer_mode) { /* when doing ftp, append ;type= if not present */ size_t len = strlen(path); diff --git a/lib/http_proxy.c b/lib/http_proxy.c index d019796b53..b2cb018c10 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -449,10 +449,10 @@ CURLcode Curl_http_proxy_create_tunnel_request( return result; if(udp_tunnel) - infof(data, "Establishing %s proxy UDP tunnel to %s:%s", + infof(data, "Establishing %s proxy UDP tunnel to %s:%u", (ver == PROXY_HTTP_V2) ? "HTTP/2" : (ver == PROXY_HTTP_V3) ? "HTTP/3" : "HTTP", - data->state.up.hostname, data->state.up.port); + dest->user_hostname, dest->port); else infof(data, "Establishing %s proxy tunnel to %s", (ver == PROXY_HTTP_V2) ? "HTTP/2" : diff --git a/lib/ldap.c b/lib/ldap.c index 29bc5efab2..b4b107a572 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -739,7 +739,8 @@ static curl_ldap_num_t ldap_url_parse2_low(struct Curl_easy *data, if(!data || !data->state.up.path || data->state.up.path[0] != '/' || - !curl_strnequal("LDAP", data->state.up.scheme, 4)) + ((data->state.origin->scheme != &Curl_scheme_ldap) && + (data->state.origin->scheme != &Curl_scheme_ldaps))) return LDAP_INVALID_SYNTAX; ludp->lud_scope = LDAP_SCOPE_BASE; diff --git a/lib/openldap.c b/lib/openldap.c index 8ec6bb27cd..ee765d8d05 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -164,7 +164,7 @@ static CURLcode oldap_map_error(int rc, CURLcode result) static CURLcode oldap_url_parse(struct Curl_easy *data, LDAPURLDesc **ludp) { CURLcode result = CURLE_OK; - int rc = LDAP_URL_ERR_BADURL; + int rc; static const char * const url_errs[] = { "success", "out of memory", @@ -180,9 +180,16 @@ static CURLcode oldap_url_parse(struct Curl_easy *data, LDAPURLDesc **ludp) }; *ludp = NULL; - if(!data->state.up.user && !data->state.up.password && - !data->state.up.options) + /* `ldap_url_parse() seems to be terrible with urls + * that have user/pass/options in it. So when we have options or + * creds from the url, fail without calling the function. + * Yes, this is super-weird code and I do not like it. */ + if((data->state.creds && (data->state.creds->source == CREDS_URL)) || + data->state.up.options) + rc = LDAP_URL_ERR_BADURL; + else rc = ldap_url_parse(Curl_bufref_ptr(&data->state.url), ludp); + if(rc != LDAP_URL_SUCCESS) { const char *msg = "url parsing problem"; @@ -605,7 +612,7 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done) if(result) goto out; - li->proto = ldap_pvt_url_scheme2proto(data->state.up.scheme); + li->proto = ldap_pvt_url_scheme2proto(data->state.origin->scheme->name); /* Initialize the SASL storage */ Curl_sasl_init(&li->sasl, data, &saslldap); @@ -614,10 +621,11 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done) if(result) goto out; - hosturl = curl_maprintf("%s://%s:%d", + hosturl = curl_maprintf("%s://%s:%u", conn->scheme->name, - (data->state.up.hostname[0] == '[') ? - data->state.up.hostname : conn->origin->hostname, + conn->origin->ipv6 ? + conn->origin->user_hostname : + conn->origin->hostname, conn->origin->port); if(!hosturl) { result = CURLE_OUT_OF_MEMORY; diff --git a/lib/peer.c b/lib/peer.c index 44bcb52f23..4a7a12d8cf 100644 --- a/lib/peer.c +++ b/lib/peer.c @@ -74,6 +74,7 @@ #include "peer.h" #include "urldata.h" #include "url.h" +#include "urlapi-int.h" #include "vtls/vtls.h" struct peer_parse { @@ -350,31 +351,28 @@ bool Curl_peer_same_destination(struct Curl_peer *p1, struct Curl_peer *p2) CURLcode Curl_peer_from_url(CURLU *uh, struct Curl_easy *data, uint16_t port_override, uint32_t scopeid_override, - struct urlpieces *up, struct Curl_peer **ppeer) { struct peer_parse pp; - char *zoneid = NULL; + char *zoneid = NULL, *scheme = NULL, *hostname = NULL; CURLUcode uc; CURLcode result; Curl_peer_unlink(ppeer); memset(&pp, 0, sizeof(pp)); - curlx_safefree(up->scheme); - uc = curl_url_get(uh, CURLUPART_SCHEME, &up->scheme, 0); + uc = curl_url_get(uh, CURLUPART_SCHEME, &scheme, 0); if(uc) return Curl_uc_to_curlcode(uc); - pp.scheme = Curl_get_scheme(up->scheme); + pp.scheme = Curl_get_scheme(scheme); if(!pp.scheme) { - failf(data, "Protocol \"%s\" not supported%s", up->scheme, + failf(data, "Protocol \"%s\" not supported%s", scheme, data->state.this_is_a_follow ? " (in redirect)" : ""); result = CURLE_UNSUPPORTED_PROTOCOL; goto out; } - curlx_safefree(up->hostname); - uc = curl_url_get(uh, CURLUPART_HOST, &up->hostname, 0); + uc = curl_url_get(uh, CURLUPART_HOST, &hostname, 0); if(uc) { if((uc == CURLUE_NO_HOST) && (pp.scheme->flags & PROTOPT_NONETWORK)) ; /* acceptable */ @@ -383,13 +381,13 @@ CURLcode Curl_peer_from_url(CURLU *uh, struct Curl_easy *data, goto out; } } - else if(strlen(up->hostname) > MAX_URL_LEN) { + else if(strlen(hostname) > MAX_URL_LEN) { failf(data, "Too long hostname (maximum is %d)", MAX_URL_LEN); result = CURLE_URL_MALFORMAT; goto out; } - pp.host_user.str = up->hostname ? up->hostname : ""; + pp.host_user.str = hostname ? hostname : ""; pp.host_user.len = strlen(pp.host_user.str); if(pp.host_user.len) { result = peer_parse_host(data, &pp, FALSE); @@ -399,7 +397,6 @@ CURLcode Curl_peer_from_url(CURLU *uh, struct Curl_easy *data, else pp.host = pp.host_user; - curlx_safefree(up->port); if(port_override) { /* if set, we use this instead of the port possibly given in the URL */ char portbuf[16]; @@ -413,7 +410,7 @@ CURLcode Curl_peer_from_url(CURLU *uh, struct Curl_easy *data, pp.port = port_override; } else { - uc = curl_url_get(uh, CURLUPART_PORT, &up->port, CURLU_DEFAULT_PORT); + uc = Curl_url_get_port(uh, &pp.port); if(uc) { if(uc == CURLUE_OUT_OF_MEMORY) { result = CURLE_OUT_OF_MEMORY; @@ -425,13 +422,6 @@ CURLcode Curl_peer_from_url(CURLU *uh, struct Curl_easy *data, } /* no port ok when not a network scheme */ } - else { - const char *p = up->port; - curl_off_t offt; - if(curlx_str_number(&p, &offt, 0xffff)) - return CURLE_URL_MALFORMAT; - pp.port = (uint16_t)offt; - } } if(scopeid_override) @@ -456,6 +446,8 @@ CURLcode Curl_peer_from_url(CURLU *uh, struct Curl_easy *data, out: peer_parse_clear(&pp); + curlx_free(scheme); + curlx_free(hostname); curlx_free(zoneid); return result; } diff --git a/lib/peer.h b/lib/peer.h index 1ceb230739..f6ed00cd48 100644 --- a/lib/peer.h +++ b/lib/peer.h @@ -25,7 +25,6 @@ ***************************************************************************/ struct Curl_scheme; -struct urlpieces; /* if peer hostname starts with this, the peer is a unix domain socket * path, e.g. the remainder after 'localhost'. */ @@ -84,7 +83,6 @@ bool Curl_peer_same_destination(struct Curl_peer *p1, struct Curl_peer *p2); CURLcode Curl_peer_from_url(CURLU *uh, struct Curl_easy *data, uint16_t port_override, uint32_t scopeid_override, - struct urlpieces *up, struct Curl_peer **ppeer); CURLcode Curl_peer_from_connect_to(struct Curl_easy *data, diff --git a/lib/url.c b/lib/url.c index ea635fd1e4..de5111920a 100644 --- a/lib/url.c +++ b/lib/url.c @@ -178,11 +178,6 @@ void Curl_freeset(struct Curl_easy *data) static void up_free(struct Curl_easy *data) { struct urlpieces *up = &data->state.up; - curlx_safefree(up->scheme); - curlx_safefree(up->hostname); - curlx_safefree(up->port); - curlx_safefree(up->user); - curlx_safefree(up->password); curlx_safefree(up->options); curlx_safefree(up->path); curlx_safefree(up->query); @@ -1381,7 +1376,6 @@ static CURLcode hsts_upgrade(struct Curl_easy *data, CURLUcode uc; CURLcode result; - curlx_safefree(data->state.up.scheme); uc = curl_url_set(uh, CURLUPART_SCHEME, "https", 0); if(uc) return Curl_uc_to_curlcode(uc); @@ -1393,7 +1387,7 @@ static CURLcode hsts_upgrade(struct Curl_easy *data, Curl_bufref_set(&data->state.url, url, 0, curl_free); result = Curl_peer_from_url(uh, data, port_override, scope_id, - &data->state.up, &data->state.origin); + &data->state.origin); if(result) return result; infof(data, "Switched from HTTP to HTTPS due to HSTS => %s", url); @@ -1549,26 +1543,28 @@ static CURLcode url_set_data_creds(struct Curl_easy *data, CURLU *uh) /* Extract credentials from the URL only if there are none OR * if no CURLOPT_USER was set. */ if(!newcreds || !Curl_creds_has_user(newcreds)) { + char *user = NULL; + char *passwd = NULL; char *udecoded = NULL; char *pdecoded = NULL; CURLUcode uc; - uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0); + uc = curl_url_get(uh, CURLUPART_USER, &user, 0); if(uc && (uc != CURLUE_NO_USER)) result = Curl_uc_to_curlcode(uc); if(!result) { - uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0); + uc = curl_url_get(uh, CURLUPART_PASSWORD, &passwd, 0); if(uc && (uc != CURLUE_NO_PASSWORD)) result = Curl_uc_to_curlcode(uc); } - if(!result && data->state.up.user) { - result = Curl_urldecode(data->state.up.user, 0, &udecoded, NULL, + if(!result && user) { + result = Curl_urldecode(user, 0, &udecoded, NULL, (data->state.origin->scheme->flags & PROTOPT_USERPWDCTRL) ? REJECT_ZERO : REJECT_CTRL); } - if(!result && data->state.up.password) { - result = Curl_urldecode(data->state.up.password, 0, &pdecoded, NULL, + if(!result && passwd) { + result = Curl_urldecode(passwd, 0, &pdecoded, NULL, (data->state.origin->scheme->flags & PROTOPT_USERPWDCTRL) ? REJECT_ZERO : REJECT_CTRL); @@ -1579,6 +1575,8 @@ static CURLcode url_set_data_creds(struct Curl_easy *data, CURLU *uh) curlx_free(udecoded); curlx_free(pdecoded); + curlx_free(passwd); + curlx_free(user); if(result) { failf(data, "error extracting credentials from URL"); goto out; @@ -2276,7 +2274,7 @@ static CURLcode url_set_data_origin_and_creds(struct Curl_easy *data) /* `uh` is now as the connection should use it, probably. */ result = Curl_peer_from_url(uh, data, port_override, scope_id, - &data->state.up, &data->state.origin); + &data->state.origin); if(result) goto out; /* The origin might get changed when HSTS applies */ diff --git a/lib/urlapi-int.h b/lib/urlapi-int.h index 4d23dd87b4..cf1fe6e7cc 100644 --- a/lib/urlapi-int.h +++ b/lib/urlapi-int.h @@ -65,4 +65,6 @@ CURLUcode Curl_junkscan(const char *url, size_t *urllen, bool allowspace); bool Curl_url_same_origin(CURLU *base, CURLU *href); +CURLUcode Curl_url_get_port(CURLU *u, uint16_t *pport); + #endif /* HEADER_CURL_URLAPI_INT_H */ diff --git a/lib/urlapi.c b/lib/urlapi.c index a664c7304b..66f00c6b42 100644 --- a/lib/urlapi.c +++ b/lib/urlapi.c @@ -2108,3 +2108,20 @@ bool Curl_url_same_origin(CURLU *base, CURLU *href) return FALSE; return TRUE; } + +CURLUcode Curl_url_get_port(CURLU *u, uint16_t *pport) +{ + if(u->port_present) { + *pport = u->portnum; + return CURLUE_OK; + } + else if(u->scheme) { + const struct Curl_scheme *s = Curl_get_scheme(u->scheme); + if(s && s->defport) { + *pport = s->defport; + return CURLUE_OK; + } + } + *pport = 0; + return CURLUE_NO_PORT; +} diff --git a/lib/urldata.h b/lib/urldata.h index 4666fa3658..8a716d5590 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -560,11 +560,6 @@ struct time_node { /* individual pieces of the URL */ struct urlpieces { - char *scheme; - char *hostname; - char *port; - char *user; - char *password; char *options; char *path; char *query; diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index d0bc13cadb..1ff7714af0 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -2586,8 +2586,8 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done) } rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_HOST, - (data->state.up.hostname[0] == '[') ? - data->state.up.hostname : conn->origin->hostname); + conn->origin->ipv6 ? + conn->origin->user_hostname : conn->origin->hostname); if(rc != SSH_OK) { failf(data, "Could not set remote host");