From: Daniel Stenberg Date: Thu, 2 Feb 2023 10:15:47 +0000 (+0100) Subject: urlapi: skip the extra dedotdot alloc if no dot in path X-Git-Tag: curl-7_88_0~77 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=63c53ea6277bbe287b254b0e313a9b8f1175f3e2;p=thirdparty%2Fcurl.git urlapi: skip the extra dedotdot alloc if no dot in path Saves an allocation for many/most URLs. Updates test 1395 accordingly Closes #10403 --- diff --git a/lib/urlapi.c b/lib/urlapi.c index f22adc7afd..0ddc5b8e12 100644 --- a/lib/urlapi.c +++ b/lib/urlapi.c @@ -783,25 +783,28 @@ static CURLUcode decode_host(struct dynbuf *host) * * RETURNS * - * an allocated dedotdotified output string + * Zero for success and 'out' set to an allocated dedotdotified string. */ -UNITTEST char *dedotdotify(const char *input, size_t clen); -UNITTEST char *dedotdotify(const char *input, size_t clen) +UNITTEST int dedotdotify(const char *input, size_t clen, char **outp); +UNITTEST int dedotdotify(const char *input, size_t clen, char **outp) { - char *out = malloc(clen + 1); char *outptr; const char *orginput = input; char *queryp; + char *out; + + *outp = NULL; + /* the path always starts with a slash, and a slash has not dot */ + if((clen < 2) || !memchr(input, '.', clen)) + return 0; + + out = malloc(clen + 1); if(!out) - return NULL; /* out of memory */ + return 1; /* out of memory */ *out = 0; /* null-terminates, for inputs like "./" */ outptr = out; - if(!*input) - /* zero length input string, return that */ - return out; - /* * To handle query-parts properly, we must find it and remove it during the * dotdot-operation and then append it again at the end to the output @@ -906,7 +909,8 @@ UNITTEST char *dedotdotify(const char *input, size_t clen) memcpy(outptr, &orginput[oindex], qlen + 1); /* include zero byte */ } - return out; + *outp = out; + return 0; /* success */ } static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags) @@ -1226,13 +1230,16 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags) if(!(flags & CURLU_PATH_AS_IS)) { /* remove ../ and ./ sequences according to RFC3986 */ - char *newp = dedotdotify((char *)path, pathlen); - if(!newp) { + char *dedot; + int err = dedotdotify((char *)path, pathlen, &dedot); + if(err) { result = CURLUE_OUT_OF_MEMORY; goto fail; } - free(u->path); - u->path = newp; + if(dedot) { + free(u->path); + u->path = dedot; + } } } diff --git a/tests/unit/unit1395.c b/tests/unit/unit1395.c index cdaa5fa756..aebb432306 100644 --- a/tests/unit/unit1395.c +++ b/tests/unit/unit1395.c @@ -24,7 +24,7 @@ #include "curlcheck.h" /* copied from urlapi.c */ -extern char *dedotdotify(const char *input, size_t clen); +extern int dedotdotify(const char *input, size_t clen, char **out); #include "memdebug.h" @@ -58,35 +58,43 @@ UNITTEST_START { "/1/./..", "/" }, { "/1/./../2", "/2" }, { "/hello/1/./../2", "/hello/2" }, - { "test/this", "test/this" }, + { "test/this", NULL }, { "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" }, - { "/", "/" }, - { "", "" }, + { "/", NULL }, + { "", NULL }, { "/.../", "/.../" }, { "./moo", "moo" }, { "../moo", "moo" }, { "/.", "/" }, { "/..", "/" }, { "/moo/..", "/" }, - { "..", "" }, - { ".", "" }, + { "/..", "/" }, + { "/.", "/" }, }; for(i = 0; i < sizeof(pairs)/sizeof(pairs[0]); i++) { - char *out = dedotdotify(pairs[i].input, strlen(pairs[i].input)); - abort_unless(out != NULL, "returned NULL!"); + char *out; + int err = dedotdotify(pairs[i].input, strlen(pairs[i].input), &out); + abort_unless(err == 0, "returned error"); + abort_if(err && out, "returned error with output"); - if(strcmp(out, pairs[i].output)) { + if(out && strcmp(out, pairs[i].output)) { fprintf(stderr, "Test %u: '%s' gave '%s' instead of '%s'\n", i, pairs[i].input, out, pairs[i].output); fail("Test case output mismatched"); fails++; } + else if(!out && pairs[i].output) { + fprintf(stderr, "Test %u: '%s' gave '%s' instead of NULL\n", + i, pairs[i].input, out); + fail("Test case output mismatched"); + fails++; + } else fprintf(stderr, "Test %u: OK\n", i); free(out);