curl: named globs in output file name for upload glob references

Use parts of text from the upload filename field when that uses globbing
by giving it a name the same way we do it for URL globs. For example, if
you upload three files to a HTTP URL and want to save the corresponding
responses in separate files:

    curl -T 'file{<num>1,2,3}' https://upload.example/ -o 'response-#<num>'

Verified by test 2014

Closes #21407
This commit is contained in:
Daniel Stenberg 2026-04-22 00:52:16 +02:00
parent 89f38c168c
commit 2238f0921c
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
7 changed files with 145 additions and 22 deletions

View file

@ -1052,11 +1052,13 @@ static CURLcode setup_outfile(struct OperationConfig *config,
return result;
}
}
else if(glob_inuse(&state->urlglob)) {
/* fill '#1' ... '#9' terms from URL pattern */
else if(glob_inuse(&state->urlglob) || glob_inuse(&state->inglob)) {
/* expand '#1' ... '#9' references from URL pattern and named references
from the upload file glob */
SANITIZEcode sc;
CURLcode result =
glob_match_url(&per->outfile, u->outfile, &state->urlglob, &sc);
glob_match_url(&per->outfile, u->outfile, &state->urlglob,
glob_inuse(&state->inglob) ? &state->inglob : NULL, &sc);
if(sc) {
if(sc == SANITIZE_ERR_OUT_OF_MEMORY)

View file

@ -703,7 +703,8 @@ CURLcode glob_next_url(char **globbed, struct URLGlob *glob)
#define MAX_OUTPUT_GLOB_LENGTH (1024 * 1024)
CURLcode glob_match_url(char **output, const char *filename,
struct URLGlob *glob, SANITIZEcode *sc)
struct URLGlob *glob, struct URLGlob *glob2,
SANITIZEcode *sc)
{
struct dynbuf dyn;
const char *ifilename = filename;
@ -741,7 +742,11 @@ CURLcode glob_match_url(char **output, const char *filename,
if(!curlx_str_until(&filename, &name, MAX_GLOBNAME_LEN, '>') &&
!curlx_str_single(&filename, '>')) {
/* find the correct glob entry */
pat = glob_find_name(glob, &name);
if(glob_inuse(glob))
pat = glob_find_name(glob, &name);
if(!pat && glob2 && glob_inuse(glob2))
/* scan the second glob list if there is one */
pat = glob_find_name(glob2, &name);
if(!pat) {
/* when the name is given correctly, it needs to be an existing glob
name, which makes this an error */

View file

@ -79,7 +79,8 @@ CURLcode glob_url(struct URLGlob *glob, const char *url, curl_off_t *urlnum,
FILE *error);
CURLcode glob_next_url(char **globbed, struct URLGlob *glob);
CURLcode glob_match_url(char **output, const char *filename,
struct URLGlob *glob, SANITIZEcode *sc);
struct URLGlob *glob, struct URLGlob *glob2,
SANITIZEcode *sc);
void glob_cleanup(struct URLGlob *glob);
bool glob_inuse(struct URLGlob *glob);