urlapi: cleanups

- move host checks together
- simplify the scheme parser loop and the end of host name parser
- avoid itermediate buffer storing in multiple places
- reduce scope for several variables
- skip the Curl_dyn_tail() call for speed
- detect IPv6 earlier and skip extra checks for such hosts
- normalize directly in dynbuf instead of itermediate buffer
- split out the IPv6 parser into its own funciton
- call the IPv6 parser directly for ipv6 addresses
- remove (unused) special treatment of % in host names
- junkscan() once in the beginning instead of scattered
- make junkscan return error code
- remove unused query management from dedotdotify()
- make Curl_parse_login_details use memchr
- more use of memchr() instead of strchr() and less strlen() calls
- make junkscan check and return the URL length

An optimized build runs one of my benchmark URL parsing programs ~41%
faster using this branch. (compared against the shipped 7.88.1 library
in Debian)

Closes #10935
This commit is contained in:
Daniel Stenberg 2023-04-11 17:06:54 +02:00
parent 233b4e4589
commit 4cfa5bcc9a
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
5 changed files with 280 additions and 365 deletions

View file

@ -231,17 +231,17 @@ static const struct testcase get_parts_list[] ={
#endif
{"https://user:password@example.net/get?this=and#but frag then", "",
CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_FRAGMENT},
CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
{"https://user:password@example.net/get?this=and what", "",
CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_QUERY},
CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
{"https://user:password@example.net/ge t?this=and-what", "",
CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_PATH},
CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
{"https://user:pass word@example.net/get?this=and-what", "",
CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_PASSWORD},
CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
{"https://u ser:password@example.net/get?this=and-what", "",
CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_USER},
CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
{"imap://user:pass;opt ion@server/path", "",
CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_LOGIN},
CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
/* no space allowed in scheme */
{"htt ps://user:password@example.net/get?this=and-what", "",
CURLU_NON_SUPPORT_SCHEME|CURLU_ALLOW_SPACE, 0, CURLUE_BAD_SCHEME},
@ -403,9 +403,9 @@ static const struct testcase get_parts_list[] ={
"https | [11] | [12] | [13] | 127abc.com | [15] | / | [16] | [17]",
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
{"https:// example.com?check", "",
CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_HOSTNAME},
CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
{"https://e x a m p l e.com?check", "",
CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_HOSTNAME},
CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
{"https://example.com?check",
"https | [11] | [12] | [13] | example.com | [15] | / | check | [17]",
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
@ -532,7 +532,7 @@ static const struct urltestcase get_url_list[] = {
{"https://\xff.127.0.0.1", "https://%FF.127.0.0.1/", 0, CURLU_URLENCODE,
CURLUE_OK},
{"https://127.-0.0.1", "https://127.-0.0.1/", 0, 0, CURLUE_BAD_HOSTNAME},
{"https://127.0. 1", "https://127.0.0.1/", 0, 0, CURLUE_BAD_HOSTNAME},
{"https://127.0. 1", "https://127.0.0.1/", 0, 0, CURLUE_MALFORMED_INPUT},
{"https://1.0x1000000", "https://1.0x1000000/", 0, 0, CURLUE_BAD_HOSTNAME},
{"https://1.2.3.256", "https://1.2.3.256/", 0, 0, CURLUE_BAD_HOSTNAME},
{"https://1.2.3.4.5", "https://1.2.3.4.5/", 0, 0, CURLUE_BAD_HOSTNAME},
@ -585,14 +585,14 @@ static const struct urltestcase get_url_list[] = {
CURLU_GUESS_SCHEME, 0, CURLUE_OK},
{"HTTP://test/", "http://test/", 0, 0, CURLUE_OK},
{"http://HO0_-st..~./", "http://HO0_-st..~./", 0, 0, CURLUE_OK},
{"http:/@example.com: 123/", "", 0, 0, CURLUE_BAD_PORT_NUMBER},
{"http:/@example.com:123 /", "", 0, 0, CURLUE_BAD_PORT_NUMBER},
{"http:/@example.com: 123/", "", 0, 0, CURLUE_MALFORMED_INPUT},
{"http:/@example.com:123 /", "", 0, 0, CURLUE_MALFORMED_INPUT},
{"http:/@example.com:123a/", "", 0, 0, CURLUE_BAD_PORT_NUMBER},
{"http://host/file\r", "", 0, 0, CURLUE_BAD_PATH},
{"http://host/file\n\x03", "", 0, 0, CURLUE_BAD_PATH},
{"http://host/file\r", "", 0, 0, CURLUE_MALFORMED_INPUT},
{"http://host/file\n\x03", "", 0, 0, CURLUE_MALFORMED_INPUT},
{"htt\x02://host/file", "",
CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_BAD_SCHEME},
{" http://host/file", "", 0, 0, CURLUE_BAD_SCHEME},
CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
{" http://host/file", "", 0, 0, CURLUE_MALFORMED_INPUT},
/* here the password ends at the semicolon and options is 'word' */
{"imap://user:pass;word@host/file",
"imap://user:pass;word@host/file",
@ -1485,7 +1485,7 @@ static int huge(void)
rc = curl_url_set(urlp, CURLUPART_URL, total, CURLU_NON_SUPPORT_SCHEME);
if((!i && (rc != CURLUE_BAD_SCHEME)) ||
(i && rc)) {
printf("URL %u: failed to parse\n", i);
printf("URL %u: failed to parse [%s]\n", i, total);
error++;
}

View file

@ -62,9 +62,9 @@ UNITTEST_START
{ "test/this/../now", "test/now" },
{ "/1../moo../foo", "/1../moo../foo"},
{ "/../../moo", "/moo"},
{ "/../../moo?andnot/../yay", "/moo?andnot/../yay"},
{ "/123?foo=/./&bar=/../", "/123?foo=/./&bar=/../"},
{ "/../moo/..?what", "/?what" },
{ "/../../moo?", "/moo?"},
{ "/123?", NULL},
{ "/../moo/..?", "/" },
{ "/", NULL },
{ "", NULL },
{ "/.../", "/.../" },