curl/add_file_name_to_url: use the libcurl URL parser

instead of the custom error-prone parser, to extract and update the path
of the given URL

Closes #9683
diff --git a/src/tool_operate.c b/src/tool_operate.c
index d45c331..544c04a 100644
--- a/src/tool_operate.c
+++ b/src/tool_operate.c
@@ -1131,12 +1131,10 @@
           /*
            * We have specified a file to upload and it isn't "-".
            */
-          char *nurl = add_file_name_to_url(per->this_url, per->uploadfile);
-          if(!nurl) {
-            result = CURLE_OUT_OF_MEMORY;
+          result = add_file_name_to_url(per->curl, &per->this_url,
+                                        per->uploadfile);
+          if(result)
             break;
-          }
-          per->this_url = nurl;
         }
         else if(per->uploadfile && stdin_upload(per->uploadfile)) {
           /* count to see if there are more than one auth bit set
diff --git a/src/tool_operhlp.c b/src/tool_operhlp.c
index 0144442..d311e8d 100644
--- a/src/tool_operhlp.c
+++ b/src/tool_operhlp.c
@@ -73,61 +73,73 @@
  * Adds the file name to the URL if it doesn't already have one.
  * url will be freed before return if the returned pointer is different
  */
-char *add_file_name_to_url(char *url, const char *filename)
+CURLcode add_file_name_to_url(CURL *curl, char **inurlp, const char *filename)
 {
-  /* If no file name part is given in the URL, we add this file name */
-  char *ptr = strstr(url, "://");
-  CURL *curl = curl_easy_init(); /* for url escaping */
-  if(!curl)
-    return NULL; /* error! */
-  if(ptr)
-    ptr += 3;
-  else
-    ptr = url;
-  ptr = strrchr(ptr, '/');
-  if(!ptr || !*++ptr) {
-    /* The URL has no file name part, add the local file name. In order
-       to be able to do so, we have to create a new URL in another
-       buffer.*/
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+  CURLU *uh = curl_url();
+  char *path = NULL;
+  if(uh) {
+    char *ptr;
+    if(curl_url_set(uh, CURLUPART_URL, *inurlp,
+                    CURLU_GUESS_SCHEME|CURLU_NON_SUPPORT_SCHEME))
+      goto fail;
+    if(curl_url_get(uh, CURLUPART_PATH, &path, 0))
+      goto fail;
 
-    /* We only want the part of the local path that is on the right
-       side of the rightmost slash and backslash. */
-    const char *filep = strrchr(filename, '/');
-    char *file2 = strrchr(filep?filep:filename, '\\');
-    char *encfile;
+    ptr = strrchr(path, '/');
+    if(!ptr || !*++ptr) {
+      /* The URL path has no file name part, add the local file name. In order
+         to be able to do so, we have to create a new URL in another buffer.*/
 
-    if(file2)
-      filep = file2 + 1;
-    else if(filep)
-      filep++;
-    else
-      filep = filename;
+      /* We only want the part of the local path that is on the right
+         side of the rightmost slash and backslash. */
+      const char *filep = strrchr(filename, '/');
+      char *file2 = strrchr(filep?filep:filename, '\\');
+      char *encfile;
 
-    /* URL encode the file name */
-    encfile = curl_easy_escape(curl, filep, 0 /* use strlen */);
-    if(encfile) {
-      char *urlbuffer;
-      if(ptr)
-        /* there is a trailing slash on the URL */
-        urlbuffer = aprintf("%s%s", url, encfile);
+      if(file2)
+        filep = file2 + 1;
+      else if(filep)
+        filep++;
       else
-        /* there is no trailing slash on the URL */
-        urlbuffer = aprintf("%s/%s", url, encfile);
+        filep = filename;
 
-      curl_free(encfile);
+      /* URL encode the file name */
+      encfile = curl_easy_escape(curl, filep, 0 /* use strlen */);
+      if(encfile) {
+        char *newpath;
+        char *newurl;
+        CURLUcode uerr;
+        if(ptr)
+          /* there is a trailing slash on the path */
+          newpath = aprintf("%s%s", path, encfile);
+        else
+          /* there is no trailing slash on the path */
+          newpath = aprintf("%s/%s", path, encfile);
 
-      if(!urlbuffer) {
-        url = NULL;
-        goto end;
+        curl_free(encfile);
+
+        if(!newpath)
+          goto fail;
+        uerr = curl_url_set(uh, CURLUPART_PATH, newpath, 0);
+        free(newpath);
+        if(uerr)
+          goto fail;
+        if(curl_url_get(uh, CURLUPART_URL, &newurl, CURLU_DEFAULT_SCHEME))
+          goto fail;
+        free(*inurlp);
+        *inurlp = newurl;
+        result = CURLE_OK;
       }
-
-      Curl_safefree(url);
-      url = urlbuffer; /* use our new URL instead! */
     }
+    else
+      /* nothing to do */
+      result = CURLE_OK;
   }
-  end:
-  curl_easy_cleanup(curl);
-  return url;
+  fail:
+  curl_url_cleanup(uh);
+  curl_free(path);
+  return result;
 }
 
 /* Extracts the name portion of the URL.
diff --git a/src/tool_operhlp.h b/src/tool_operhlp.h
index c48d7ec..8018d1a 100644
--- a/src/tool_operhlp.h
+++ b/src/tool_operhlp.h
@@ -33,7 +33,7 @@
 
 bool stdin_upload(const char *uploadfile);
 
-char *add_file_name_to_url(char *url, const char *filename);
+CURLcode add_file_name_to_url(CURL *curl, char **inurlp, const char *filename);
 
 CURLcode get_url_file_name(char **filename, const char *url);
 
diff --git a/tests/data/test58 b/tests/data/test58
index 01d7189..75765b2 100644
--- a/tests/data/test58
+++ b/tests/data/test58
@@ -36,7 +36,7 @@
 # Verify data after the test has been "shot"
 <verify>
 <protocol>
-PUT /we/want/%TESTNUMBERte%5B%5Dst.txt HTTP/1.1

+PUT /we/want/%TESTNUMBERte%5b%5dst.txt HTTP/1.1

 Host: %HOSTIP:%HTTPPORT

 User-Agent: curl/%VERSION

 Accept: */*