From e49e5eaa1069a4dfb0ece4a6d833bf51341ef73a Mon Sep 17 00:00:00 2001 From: Patrick Monnerat Date: Tue, 19 Feb 2019 17:08:58 +0100 Subject: cli tool: fix mime post with --disable-libcurl-option configure option Reported-by: Marcel Raad Fixes #3576 Closes #3583 --- src/tool_cfgable.c | 8 +-- src/tool_cfgable.h | 3 +- src/tool_formparse.c | 114 ++++++++++++++++++++++++++++++++-- src/tool_formparse.h | 4 +- src/tool_getparam.c | 4 +- src/tool_operate.c | 3 + src/tool_setopt.c | 170 ++++++++++++++++++--------------------------------- src/tool_setopt.h | 2 +- 8 files changed, 181 insertions(+), 127 deletions(-) diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c index 6d4a0ed9b..cf5212bab 100644 --- a/src/tool_cfgable.c +++ b/src/tool_cfgable.c @@ -144,10 +144,10 @@ static void free_config_fields(struct OperationConfig *config) curl_slist_free_all(config->headers); curl_slist_free_all(config->proxyheaders); - if(config->mimepost) { - tool_mime_free(config->mimepost); - config->mimepost = NULL; - } + curl_mime_free(config->mimepost); + config->mimepost = NULL; + tool_mime_free(config->mimeroot); + config->mimeroot = NULL; config->mimecurrent = NULL; curl_slist_free_all(config->telnet_options); diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 0ebe947ae..2adfcae23 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -178,8 +178,9 @@ struct OperationConfig { curl_off_t condtime; struct curl_slist *headers; struct curl_slist *proxyheaders; - tool_mime *mimepost; + tool_mime *mimeroot; tool_mime *mimecurrent; + curl_mime *mimepost; struct curl_slist *telnet_options; struct curl_slist *resolve; struct curl_slist *connect_to; diff --git a/src/tool_formparse.c b/src/tool_formparse.c index bba1d07e7..49993470b 100644 --- a/src/tool_formparse.c +++ b/src/tool_formparse.c @@ -166,7 +166,6 @@ void tool_mime_free(tool_mime *mime) tool_mime_free(mime->subparts); if(mime->prev) tool_mime_free(mime->prev); - curl_mime_free(mime->handle); CONST_SAFEFREE(mime->name); CONST_SAFEFREE(mime->filename); CONST_SAFEFREE(mime->type); @@ -237,6 +236,109 @@ int tool_mime_stdin_seek(void *instream, curl_off_t offset, int whence) return CURL_SEEKFUNC_OK; } +/* Translate an internal mime tree into a libcurl mime tree. */ + +static CURLcode tool2curlparts(CURL *curl, tool_mime *m, curl_mime *mime) +{ + CURLcode ret = CURLE_OK; + curl_mimepart *part = NULL; + curl_mime *submime = NULL; + const char *filename = NULL; + + if(m) { + ret = tool2curlparts(curl, m->prev, mime); + if(!ret) { + part = curl_mime_addpart(mime); + if(!part) + ret = CURLE_OUT_OF_MEMORY; + } + if(!ret) { + filename = m->filename; + switch(m->kind) { + case TOOLMIME_PARTS: + ret = tool2curlmime(curl, m, &submime); + if(!ret) { + ret = curl_mime_subparts(part, submime); + if(ret) + curl_mime_free(submime); + } + break; + + case TOOLMIME_DATA: +#ifdef CURL_DOES_CONVERSIONS + /* Our data is always textual: convert it to ASCII. */ + { + size_t size = strlen(m->data); + char *cp = malloc(size + 1); + + if(!cp) + ret = CURLE_OUT_OF_MEMORY; + else { + memcpy(cp, m->data, size + 1); + ret = convert_to_network(cp, size); + if(!ret) + ret = curl_mime_data(part, cp, CURL_ZERO_TERMINATED); + free(cp); + } + } +#else + ret = curl_mime_data(part, m->data, CURL_ZERO_TERMINATED); +#endif + break; + + case TOOLMIME_FILE: + case TOOLMIME_FILEDATA: + ret = curl_mime_filedata(part, m->data); + if(!ret && m->kind == TOOLMIME_FILEDATA && !filename) + ret = curl_mime_filename(part, NULL); + break; + + case TOOLMIME_STDIN: + if(!filename) + filename = "-"; + /* FALLTHROUGH */ + case TOOLMIME_STDINDATA: + ret = curl_mime_data_cb(part, m->size, + (curl_read_callback) tool_mime_stdin_read, + (curl_seek_callback) tool_mime_stdin_seek, + NULL, m); + break; + + default: + /* Other cases not possible in this context. */ + break; + } + } + if(!ret && filename) + ret = curl_mime_filename(part, filename); + if(!ret) + ret = curl_mime_type(part, m->type); + if(!ret) + ret = curl_mime_headers(part, m->headers, 0); + if(!ret) + ret = curl_mime_encoder(part, m->encoder); + if(!ret) + ret = curl_mime_name(part, m->name); + } + return ret; +} + +CURLcode tool2curlmime(CURL *curl, tool_mime *m, curl_mime **mime) +{ + CURLcode ret = CURLE_OK; + + *mime = curl_mime_init(curl); + if(!*mime) + ret = CURLE_OUT_OF_MEMORY; + else + ret = tool2curlparts(curl, m->subparts, *mime); + if(ret) { + curl_mime_free(*mime); + *mime = NULL; + } + return ret; +} + /* * helper function to get a word from form param * after call get_parm_word, str either point to string end @@ -633,7 +735,7 @@ static int get_param_part(struct OperationConfig *config, char endchar, int formparse(struct OperationConfig *config, const char *input, - tool_mime **mimepost, + tool_mime **mimeroot, tool_mime **mimecurrent, bool literal_value) { @@ -652,8 +754,8 @@ int formparse(struct OperationConfig *config, /* Allocate the main mime structure if needed. */ if(!*mimecurrent) { - NULL_CHECK(*mimepost, tool_mime_new_parts(NULL), 1); - *mimecurrent = *mimepost; + NULL_CHECK(*mimeroot, tool_mime_new_parts(NULL), 1); + *mimecurrent = *mimeroot; } /* Make a copy we can overwrite. */ @@ -683,7 +785,7 @@ int formparse(struct OperationConfig *config, } else if(!name && !strcmp(contp, ")") && !literal_value) { /* Ending a multipart. */ - if(*mimecurrent == *mimepost) { + if(*mimecurrent == *mimeroot) { warnf(config->global, "no multipart to terminate!\n"); Curl_safefree(contents); return 6; @@ -721,6 +823,7 @@ int formparse(struct OperationConfig *config, tool_mime_new_filedata(subparts, data, TRUE, &res), 9); part->headers = headers; headers = NULL; + part->config = config->global; if(res == CURLE_READ_ERROR) { /* An error occurred while reading stdin: if read has started, issue the error now. Else, delay it until processed by @@ -758,6 +861,7 @@ int formparse(struct OperationConfig *config, &res), 15); part->headers = headers; headers = NULL; + part->config = config->global; if(res == CURLE_READ_ERROR) { /* An error occurred while reading stdin: if read has started, issue the error now. Else, delay it until processed by diff --git a/src/tool_formparse.h b/src/tool_formparse.h index 203f5ab30..750fe451f 100644 --- a/src/tool_formparse.h +++ b/src/tool_formparse.h @@ -50,7 +50,6 @@ struct tool_mime { struct curl_slist *headers; /* User-defined headers. */ /* TOOLMIME_PARTS fields. */ tool_mime *subparts; /* Part's subparts. */ - curl_mime *handle; /* Libcurl mime handle. */ /* TOOLMIME_STDIN/TOOLMIME_STDINDATA fields. */ curl_off_t origin; /* Stdin read origin offset. */ curl_off_t size; /* Stdin data size. */ @@ -64,9 +63,10 @@ int tool_mime_stdin_seek(void *instream, curl_off_t offset, int whence); int formparse(struct OperationConfig *config, const char *input, - tool_mime **mimepost, + tool_mime **mimeroot, tool_mime **mimecurrent, bool literal_value); +CURLcode tool2curlmime(CURL *curl, tool_mime *m, curl_mime **mime); void tool_mime_free(tool_mime *mime); #endif /* HEADER_CURL_TOOL_FORMPARSE_H */ diff --git a/src/tool_getparam.c b/src/tool_getparam.c index c7ba5f243..82ba8b215 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -1691,7 +1691,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ to sort this out slowly and carefully */ if(formparse(config, nextarg, - &config->mimepost, + &config->mimeroot, &config->mimecurrent, (subletter == 's')?TRUE:FALSE)) /* 's' is literal string */ return PARAM_BAD_USE; diff --git a/src/tool_operate.c b/src/tool_operate.c index 7d58dde27..a8698285d 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -945,6 +945,9 @@ static CURLcode operate_do(struct GlobalConfig *global, config->postfieldsize); break; case HTTPREQ_MIMEPOST: + result = tool2curlmime(curl, config->mimeroot, &config->mimepost); + if(result) + goto show_error; my_setopt_mimepost(curl, CURLOPT_MIMEPOST, config->mimepost); break; default: diff --git a/src/tool_setopt.c b/src/tool_setopt.c index 26102d312..745b4546e 100644 --- a/src/tool_setopt.c +++ b/src/tool_setopt.c @@ -414,60 +414,45 @@ static CURLcode libcurl_generate_slist(struct curl_slist *slist, int *slistno) static CURLcode libcurl_generate_mime(CURL *curl, struct GlobalConfig *config, tool_mime *toolmime, - curl_mime **mime, int *mimeno); /* Forward. */ -/* Wrapper to build and generate source code for a mime part. */ +/* Wrapper to generate source code for a mime part. */ static CURLcode libcurl_generate_mime_part(CURL *curl, struct GlobalConfig *config, tool_mime *part, - curl_mime *mime, int mimeno) { CURLcode ret = CURLE_OK; - curl_mimepart *mimepart; int submimeno = 0; - curl_mime *submime = NULL; char *escaped = NULL; const char *data = NULL; const char *filename = part->filename; /* Parts are linked in reverse order. */ if(part->prev) { - ret = libcurl_generate_mime_part(curl, config, part->prev, mime, mimeno); + ret = libcurl_generate_mime_part(curl, config, part->prev, mimeno); if(ret) return ret; } /* Create the part. */ - mimepart = curl_mime_addpart(mime); - NULL_CHECK(mimepart); - if(config->libcurl) - CODE2("part%d = curl_mime_addpart(mime%d);", mimeno, mimeno); + CODE2("part%d = curl_mime_addpart(mime%d);", mimeno, mimeno); switch(part->kind) { case TOOLMIME_PARTS: - ret = libcurl_generate_mime(curl, config, part, &submime, &submimeno); + ret = libcurl_generate_mime(curl, config, part, &submimeno); if(!ret) { - ret = curl_mime_subparts(mimepart, submime); - if(!ret) { - submime = NULL; - if(config->libcurl) { - CODE2("curl_mime_subparts(part%d, mime%d);", mimeno, submimeno); - CODE1("mime%d = NULL;", submimeno); /* Avoid freeing in CLEAN. */ - } - } + CODE2("curl_mime_subparts(part%d, mime%d);", mimeno, submimeno); + CODE1("mime%d = NULL;", submimeno); /* Avoid freeing in CLEAN. */ } break; case TOOLMIME_DATA: #ifdef CURL_DOES_CONVERSIONS - if(config->libcurl) { - /* Data will be set in ASCII, thus issue a comment with clear text. */ - escaped = c_escape(part->data, CURL_ZERO_TERMINATED); - NULL_CHECK(escaped); - CODE1("/* \"%s\" */", escaped); - } + /* Data will be set in ASCII, thus issue a comment with clear text. */ + escaped = c_escape(part->data, CURL_ZERO_TERMINATED); + NULL_CHECK(escaped); + CODE1("/* \"%s\" */", escaped); /* Our data is always textual: convert it to ASCII. */ { @@ -482,9 +467,7 @@ static CURLcode libcurl_generate_mime_part(CURL *curl, #else data = part->data; #endif - if(!ret) - ret = curl_mime_data(mimepart, data, CURL_ZERO_TERMINATED); - if(!ret && config->libcurl) { + if(!ret) { Curl_safefree(escaped); escaped = c_escape(data, CURL_ZERO_TERMINATED); NULL_CHECK(escaped); @@ -495,16 +478,11 @@ static CURLcode libcurl_generate_mime_part(CURL *curl, case TOOLMIME_FILE: case TOOLMIME_FILEDATA: - ret = curl_mime_filedata(mimepart, part->data); - if(!ret && config->libcurl) { - escaped = c_escape(part->data, CURL_ZERO_TERMINATED); - NULL_CHECK(escaped); - CODE2("curl_mime_filedata(part%d, \"%s\");", mimeno, escaped); - } - if(!ret && part->kind == TOOLMIME_FILEDATA && !filename) { - ret = curl_mime_filename(mimepart, NULL); - if(!ret && config->libcurl) - CODE1("curl_mime_filename(part%d, NULL);", mimeno); + escaped = c_escape(part->data, CURL_ZERO_TERMINATED); + NULL_CHECK(escaped); + CODE2("curl_mime_filedata(part%d, \"%s\");", mimeno, escaped); + if(part->kind == TOOLMIME_FILEDATA && !filename) { + CODE1("curl_mime_filename(part%d, NULL);", mimeno); } break; @@ -513,17 +491,10 @@ static CURLcode libcurl_generate_mime_part(CURL *curl, filename = "-"; /* FALLTHROUGH */ case TOOLMIME_STDINDATA: - part->config = config; - ret = curl_mime_data_cb(mimepart, part->size, - (curl_read_callback) tool_mime_stdin_read, - (curl_seek_callback) tool_mime_stdin_seek, - NULL, part); - if(!ret && config->libcurl) { - /* Can only be reading stdin in the current context. */ - CODE1("curl_mime_data_cb(part%d, -1, (curl_read_callback) fread, \\", - mimeno); - CODE0(" (curl_seek_callback) fseek, NULL, stdin);"); - } + /* Can only be reading stdin in the current context. */ + CODE1("curl_mime_data_cb(part%d, -1, (curl_read_callback) fread, \\", + mimeno); + CODE0(" (curl_seek_callback) fseek, NULL, stdin);"); break; default: /* Other cases not possible in this context. */ @@ -531,55 +502,40 @@ static CURLcode libcurl_generate_mime_part(CURL *curl, } if(!ret && part->encoder) { - ret = curl_mime_encoder(mimepart, part->encoder); - if(!ret && config->libcurl) { - Curl_safefree(escaped); - escaped = c_escape(part->encoder, CURL_ZERO_TERMINATED); - NULL_CHECK(escaped); - CODE2("curl_mime_encoder(part%d, \"%s\");", mimeno, escaped); - } + Curl_safefree(escaped); + escaped = c_escape(part->encoder, CURL_ZERO_TERMINATED); + NULL_CHECK(escaped); + CODE2("curl_mime_encoder(part%d, \"%s\");", mimeno, escaped); } if(!ret && filename) { - ret = curl_mime_filename(mimepart, filename); - if(!ret && config->libcurl) { - Curl_safefree(escaped); - escaped = c_escape(filename, CURL_ZERO_TERMINATED); - NULL_CHECK(escaped); - CODE2("curl_mime_filename(part%d, \"%s\");", mimeno, escaped); - } + Curl_safefree(escaped); + escaped = c_escape(filename, CURL_ZERO_TERMINATED); + NULL_CHECK(escaped); + CODE2("curl_mime_filename(part%d, \"%s\");", mimeno, escaped); } if(!ret && part->name) { - ret = curl_mime_name(mimepart, part->name); - if(!ret && config->libcurl) { - Curl_safefree(escaped); - escaped = c_escape(part->name, CURL_ZERO_TERMINATED); - NULL_CHECK(escaped); - CODE2("curl_mime_name(part%d, \"%s\");", mimeno, escaped); - } + Curl_safefree(escaped); + escaped = c_escape(part->name, CURL_ZERO_TERMINATED); + NULL_CHECK(escaped); + CODE2("curl_mime_name(part%d, \"%s\");", mimeno, escaped); } if(!ret && part->type) { - ret = curl_mime_type(mimepart, part->type); - if(!ret && config->libcurl) { - Curl_safefree(escaped); - escaped = c_escape(part->type, CURL_ZERO_TERMINATED); - NULL_CHECK(escaped); - CODE2("curl_mime_type(part%d, \"%s\");", mimeno, escaped); - } + Curl_safefree(escaped); + escaped = c_escape(part->type, CURL_ZERO_TERMINATED); + NULL_CHECK(escaped); + CODE2("curl_mime_type(part%d, \"%s\");", mimeno, escaped); } if(!ret && part->headers) { - ret = curl_mime_headers(mimepart, part->headers, 0); - if(!ret && config->libcurl) { - int slistno; - - ret = libcurl_generate_slist(part->headers, &slistno); - if(!ret) { - CODE2("curl_mime_headers(part%d, slist%d, 1);", mimeno, slistno); - CODE1("slist%d = NULL;", slistno); /* Prevent CLEANing. */ - } + int slistno; + + ret = libcurl_generate_slist(part->headers, &slistno); + if(!ret) { + CODE2("curl_mime_headers(part%d, slist%d, 1);", mimeno, slistno); + CODE1("slist%d = NULL;", slistno); /* Prevent CLEANing. */ } } @@ -589,38 +545,30 @@ nomem: free((char *) data); #endif - curl_mime_free(submime); Curl_safefree(escaped); return ret; } -/* Wrapper to build and generate source code for a mime structure. */ +/* Wrapper to generate source code for a mime structure. */ static CURLcode libcurl_generate_mime(CURL *curl, struct GlobalConfig *config, tool_mime *toolmime, - curl_mime **mime, int *mimeno) { CURLcode ret = CURLE_OK; - *mime = curl_mime_init(curl); - NULL_CHECK(*mime); - - if(config->libcurl) { - /* May need several mime variables, so invent name. */ - *mimeno = ++easysrc_mime_count; - DECL1("curl_mime *mime%d;", *mimeno); - DATA1("mime%d = NULL;", *mimeno); - CODE1("mime%d = curl_mime_init(hnd);", *mimeno); - CLEAN1("curl_mime_free(mime%d);", *mimeno); - CLEAN1("mime%d = NULL;", *mimeno); - } + /* May need several mime variables, so invent name. */ + *mimeno = ++easysrc_mime_count; + DECL1("curl_mime *mime%d;", *mimeno); + DATA1("mime%d = NULL;", *mimeno); + CODE1("mime%d = curl_mime_init(hnd);", *mimeno); + CLEAN1("curl_mime_free(mime%d);", *mimeno); + CLEAN1("mime%d = NULL;", *mimeno); if(toolmime->subparts) { - if(config->libcurl) - DECL1("curl_mimepart *part%d;", *mimeno); + DECL1("curl_mimepart *part%d;", *mimeno); ret = libcurl_generate_mime_part(curl, config, - toolmime->subparts, *mime, *mimeno); + toolmime->subparts, *mimeno); } nomem: @@ -630,18 +578,16 @@ nomem: /* setopt wrapper for CURLOPT_MIMEPOST */ CURLcode tool_setopt_mimepost(CURL *curl, struct GlobalConfig *config, const char *name, CURLoption tag, - tool_mime *mimepost) + curl_mime *mimepost) { - CURLcode ret = CURLE_OK; + CURLcode ret = curl_easy_setopt(curl, tag, mimepost); int mimeno = 0; - ret = libcurl_generate_mime(curl, config, mimepost, - &mimepost->handle, &mimeno); - - if(!ret) { - ret = curl_easy_setopt(curl, tag, mimepost->handle); + if(!ret && config->libcurl) { + ret = libcurl_generate_mime(curl, config, + config->current->mimeroot, &mimeno); - if(config->libcurl && !ret) + if(!ret) CODE2("curl_easy_setopt(hnd, %s, mime%d);", name, mimeno); } diff --git a/src/tool_setopt.h b/src/tool_setopt.h index 4a03a06fc..663041f65 100644 --- a/src/tool_setopt.h +++ b/src/tool_setopt.h @@ -89,7 +89,7 @@ CURLcode tool_setopt_bitmask(CURL *curl, struct GlobalConfig *config, const NameValueUnsigned *nv, long lval); CURLcode tool_setopt_mimepost(CURL *curl, struct GlobalConfig *config, const char *name, CURLoption tag, - tool_mime *mimepost); + curl_mime *mimepost); CURLcode tool_setopt_slist(CURL *curl, struct GlobalConfig *config, const char *name, CURLoption tag, struct curl_slist *list); -- cgit v1.2.1