mirror of
https://github.com/curl/curl.git
synced 2026-07-10 06:47:18 +03:00
urlapi: do not keep an internal port string
Do not allocated an internal port string, just keep and number and a bit if it is present. Format the port string in a local buffer when someone asks for it and copy that. This avoid the format/alloc penalty when parsing URLs and no one ever asking for the port string. (And there will be a method to get the uint16_t value directly in another PR) Closes #22167
This commit is contained in:
parent
d2fe26cfe2
commit
26c6a4d898
2 changed files with 49 additions and 45 deletions
|
|
@ -34,11 +34,11 @@ struct Curl_URL {
|
|||
char *options; /* IMAP only? */
|
||||
char *host;
|
||||
char *zoneid; /* for numerical IPv6 addresses */
|
||||
char *port;
|
||||
char *path;
|
||||
char *query;
|
||||
char *fragment;
|
||||
unsigned short portnum; /* the numerical version (if 'port' is set) */
|
||||
uint16_t portnum; /* the numerical port if present */
|
||||
BIT(port_present); /* to support missing port */
|
||||
BIT(query_present); /* to support blank */
|
||||
BIT(fragment_present); /* to support blank */
|
||||
BIT(guessed_scheme); /* when a URL without scheme is parsed */
|
||||
|
|
|
|||
90
lib/urlapi.c
90
lib/urlapi.c
|
|
@ -73,7 +73,6 @@ static void free_urlhandle(struct Curl_URL *u)
|
|||
curlx_free(u->options);
|
||||
curlx_free(u->host);
|
||||
curlx_free(u->zoneid);
|
||||
curlx_free(u->port);
|
||||
curlx_free(u->path);
|
||||
curlx_free(u->query);
|
||||
curlx_free(u->fragment);
|
||||
|
|
@ -358,6 +357,8 @@ UNITTEST CURLUcode parse_port(struct Curl_URL *u, struct dynbuf *host,
|
|||
/*
|
||||
* Find the end of an IPv6 address on the ']' ending bracket.
|
||||
*/
|
||||
u->portnum = 0;
|
||||
u->port_present = FALSE;
|
||||
if(hostname[0] == '[') {
|
||||
portptr = strchr(hostname, ']');
|
||||
if(!portptr)
|
||||
|
|
@ -393,12 +394,8 @@ UNITTEST CURLUcode parse_port(struct Curl_URL *u, struct dynbuf *host,
|
|||
if(curlx_str_number(&portptr, &port, 0xffff) || *portptr)
|
||||
return CURLUE_BAD_PORT_NUMBER;
|
||||
|
||||
u->portnum = (unsigned short)port;
|
||||
/* generate a new port number string to get rid of leading zeroes etc */
|
||||
curlx_free(u->port);
|
||||
u->port = curl_maprintf("%" CURL_FORMAT_CURL_OFF_T, port);
|
||||
if(!u->port)
|
||||
return CURLUE_OUT_OF_MEMORY;
|
||||
u->portnum = (uint16_t)port;
|
||||
u->port_present = TRUE;
|
||||
}
|
||||
|
||||
return CURLUE_OK;
|
||||
|
|
@ -1344,12 +1341,12 @@ CURLU *curl_url_dup(const CURLU *in)
|
|||
DUP(u, in, password);
|
||||
DUP(u, in, options);
|
||||
DUP(u, in, host);
|
||||
DUP(u, in, port);
|
||||
DUP(u, in, path);
|
||||
DUP(u, in, query);
|
||||
DUP(u, in, fragment);
|
||||
DUP(u, in, zoneid);
|
||||
u->portnum = in->portnum;
|
||||
u->port_present = in->port_present;
|
||||
u->fragment_present = in->fragment_present;
|
||||
u->query_present = in->query_present;
|
||||
}
|
||||
|
|
@ -1484,7 +1481,7 @@ static CURLUcode urlget_url(const CURLU *u, char **part, unsigned int flags)
|
|||
else {
|
||||
const char *scheme;
|
||||
char *options = u->options;
|
||||
char *port = u->port;
|
||||
char *port = NULL;
|
||||
const struct Curl_scheme *h = NULL;
|
||||
char schemebuf[MAX_SCHEME_LEN + 5];
|
||||
if(u->scheme)
|
||||
|
|
@ -1494,19 +1491,26 @@ static CURLUcode urlget_url(const CURLU *u, char **part, unsigned int flags)
|
|||
else
|
||||
return CURLUE_NO_SCHEME;
|
||||
|
||||
if(u->port_present) {
|
||||
curl_msnprintf(portbuf, sizeof(portbuf), "%u", u->portnum);
|
||||
port = portbuf;
|
||||
}
|
||||
|
||||
h = Curl_get_scheme(scheme);
|
||||
if(h) {
|
||||
if(!port && (flags & CURLU_DEFAULT_PORT)) {
|
||||
if(!u->port_present && (flags & CURLU_DEFAULT_PORT)) {
|
||||
/* there is no stored port number, but asked to deliver a default one
|
||||
for the scheme */
|
||||
curl_msnprintf(portbuf, sizeof(portbuf), "%u", h->defport);
|
||||
port = portbuf;
|
||||
}
|
||||
else if(port && (h->defport == u->portnum) &&
|
||||
(flags & CURLU_NO_DEFAULT_PORT))
|
||||
else if(u->port_present && (h->defport == u->portnum) &&
|
||||
(flags & CURLU_NO_DEFAULT_PORT)) {
|
||||
/* there is a stored port number, but asked to inhibit if it matches
|
||||
the default port for the scheme */
|
||||
port = NULL;
|
||||
}
|
||||
|
||||
if(!(h->flags & PROTOPT_URLOPTIONS))
|
||||
options = NULL;
|
||||
}
|
||||
|
|
@ -1614,10 +1618,24 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
|
|||
ifmissing = CURLUE_NO_ZONEID;
|
||||
break;
|
||||
case CURLUPART_PORT:
|
||||
ptr = u->port;
|
||||
ptr = NULL;
|
||||
ifmissing = CURLUE_NO_PORT;
|
||||
flags &= ~U_CURLU_URLDECODE; /* never for port */
|
||||
if(!ptr && (flags & CURLU_DEFAULT_PORT) && u->scheme) {
|
||||
if(u->port_present) {
|
||||
const struct Curl_scheme *h = u->scheme ?
|
||||
Curl_get_scheme(u->scheme) : NULL;
|
||||
/* there is a stored port number, but ask to inhibit if
|
||||
it matches the default one for the scheme */
|
||||
if(h && (h->defport == u->portnum) &&
|
||||
(flags & CURLU_NO_DEFAULT_PORT)) {
|
||||
ptr = NULL;
|
||||
}
|
||||
else {
|
||||
curl_msnprintf(portbuf, sizeof(portbuf), "%u", u->portnum);
|
||||
ptr = portbuf;
|
||||
}
|
||||
}
|
||||
else if((flags & CURLU_DEFAULT_PORT) && u->scheme) {
|
||||
/* there is no stored port number, but asked to deliver
|
||||
a default one for the scheme */
|
||||
const struct Curl_scheme *h = Curl_get_scheme(u->scheme);
|
||||
|
|
@ -1626,14 +1644,6 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
|
|||
ptr = portbuf;
|
||||
}
|
||||
}
|
||||
else if(ptr && u->scheme) {
|
||||
/* there is a stored port number, but ask to inhibit if
|
||||
it matches the default one for the scheme */
|
||||
const struct Curl_scheme *h = Curl_get_scheme(u->scheme);
|
||||
if(h && (h->defport == u->portnum) &&
|
||||
(flags & CURLU_NO_DEFAULT_PORT))
|
||||
ptr = NULL;
|
||||
}
|
||||
break;
|
||||
case CURLUPART_PATH:
|
||||
ptr = u->path;
|
||||
|
|
@ -1700,7 +1710,6 @@ static CURLUcode set_url_scheme(CURLU *u, const char *scheme,
|
|||
|
||||
static CURLUcode set_url_port(CURLU *u, const char *provided_port)
|
||||
{
|
||||
char *tmp;
|
||||
curl_off_t port;
|
||||
if(!ISDIGIT(provided_port[0]))
|
||||
/* not a number */
|
||||
|
|
@ -1708,12 +1717,8 @@ static CURLUcode set_url_port(CURLU *u, const char *provided_port)
|
|||
if(curlx_str_number(&provided_port, &port, 0xffff) || *provided_port)
|
||||
/* weirdly provided number, not good! */
|
||||
return CURLUE_BAD_PORT_NUMBER;
|
||||
tmp = curl_maprintf("%" CURL_FORMAT_CURL_OFF_T, port);
|
||||
if(!tmp)
|
||||
return CURLUE_OUT_OF_MEMORY;
|
||||
curlx_free(u->port);
|
||||
u->port = tmp;
|
||||
u->portnum = (unsigned short)port;
|
||||
u->portnum = (uint16_t)port;
|
||||
u->port_present = TRUE;
|
||||
return CURLUE_OK;
|
||||
}
|
||||
|
||||
|
|
@ -1796,7 +1801,7 @@ static CURLUcode urlset_clear(CURLU *u, CURLUPart what)
|
|||
break;
|
||||
case CURLUPART_PORT:
|
||||
u->portnum = 0;
|
||||
curlx_safefree(u->port);
|
||||
u->port_present = FALSE;
|
||||
break;
|
||||
case CURLUPART_PATH:
|
||||
curlx_safefree(u->path);
|
||||
|
|
@ -2077,26 +2082,25 @@ bool Curl_url_same_origin(CURLU *base, CURLU *href)
|
|||
if(href->host) {
|
||||
if(!curl_strequal(base->host, href->host))
|
||||
return FALSE;
|
||||
if(!curl_strequal(base->zoneid ? base->zoneid : "",
|
||||
href->zoneid ? href->zoneid : ""))
|
||||
return FALSE;
|
||||
if(!curl_strequal(base->port, href->port)) {
|
||||
/* This may still match if only one has an explicit port
|
||||
* and it is the default for the scheme. */
|
||||
if(base->port && href->port)
|
||||
return FALSE;
|
||||
|
||||
if(base->port_present != href->port_present) {
|
||||
/* one is present, one is not */
|
||||
s = Curl_get_scheme(base->scheme);
|
||||
if(!s) /* Cannot match default port for unknown scheme */
|
||||
return FALSE;
|
||||
|
||||
/* The port which is set must be the default one */
|
||||
if((base->port && (base->portnum != s->defport)) ||
|
||||
(href->port && (href->portnum != s->defport)))
|
||||
/* to match, the present one must be the default port */
|
||||
if((base->port_present && (base->portnum != s->defport)) ||
|
||||
(href->port_present && (href->portnum != s->defport)))
|
||||
return FALSE;
|
||||
}
|
||||
else if(base->portnum != href->portnum) /* both present or missing */
|
||||
return FALSE;
|
||||
|
||||
if(!curl_strequal(base->zoneid ? base->zoneid : "",
|
||||
href->zoneid ? href->zoneid : ""))
|
||||
return FALSE;
|
||||
}
|
||||
else if(href->port) /* no host in href, then there must be no port */
|
||||
else if(href->port_present) /* no host in href, then there must be no port */
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue