urlapi: avoid dedotdotify() if possible

The dedotdotify() function that removes ./ and ../ sequences from paths
juggles memory and is slow. Now needs_dedotdot() is called first to
determine if the removal process is necessary and otherwise avoids doing
it. Avoids unnecessary memory operations.

Adjusted unit test 1395 accordingly because now a lot of input strings
return NULL for "no change necessary".

Suggested-by: Max Dymond

Closes #22557
This commit is contained in:
Daniel Stenberg 2026-08-12 12:11:37 +02:00
parent da04aa96ab
commit eae88a7473
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
2 changed files with 56 additions and 33 deletions

View file

@ -750,6 +750,29 @@ static bool is_dot(const char **str, size_t *clen)
#define ISSLASH(x) ((x) == '/')
/* prescan the string to see if it needs work */
static bool needs_dedotdot(const char *p, size_t pn)
{
/* a single byte path cannot be cleaned up */
if(pn < 2)
return FALSE;
while(pn) {
if(is_dot(&p, &pn)) {
/* "./" or dot before end of string */
if(!pn || ISSLASH(*p))
return TRUE;
/* "../" or ".." before end of string */
else if(is_dot(&p, &pn) && (!pn || ISSLASH(*p)))
return TRUE;
}
else {
p++;
pn--;
}
}
return FALSE;
}
/*
* dedotdotify()
*
@ -761,7 +784,8 @@ static bool is_dot(const char **str, size_t *clen)
*
* RETURNS
*
* Zero for success and 'out' set to an allocated dedotdotified string.
* Zero for success and 'out' set to an allocated string (or NULL if there's
* nothing to do).
*
* @unittest 1395
*/
@ -776,8 +800,7 @@ UNITTEST int dedotdotify(const char *input, size_t clen, char **outp)
size_t dlen = clen;
*outp = NULL;
/* a single byte path cannot be cleaned up */
if(clen < 2)
if(!needs_dedotdot(input, clen))
return 0;
curlx_dyn_init(&out, clen + 1);