diff --git a/CHANGES b/CHANGES index 88a7affca..19074e2c3 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,14 @@ Changelog +Daniel S (20 Nov 2007) +- Fixed a very long-lasting mprintf() bug that occured when we did "%.*s%s", + since the second %s would then wrongly used the numerical precision argument + instead and crash. + +- Introuced --data-urlencode to the curl tool for easier url encoding of the + data sent in a post. + Daniel S (18 Nov 2007) - Rob Crittenden fixed SSL connections with NSS done with the multi-interface diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 8106e9d7a..7fa596273 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -1,7 +1,7 @@ Curl and libcurl 7.17.2 Public curl releases: 103 - Command line options: 121 + Command line options: 122 curl_easy_setopt() options: 147 Public functions in libcurl: 55 Public web site mirrors: 42 @@ -10,7 +10,7 @@ Curl and libcurl 7.17.2 This release includes the following changes: - o + o --data-urlencode was added This release includes the following bugfixes: diff --git a/docs/curl.1 b/docs/curl.1 index 0d0a3a12f..b5d5eb788 100644 --- a/docs/curl.1 +++ b/docs/curl.1 @@ -261,6 +261,20 @@ the \fI--data-ascii\fP option, this is for you. If this option is used several times, the ones following the first will append data. +.IP "--data-urlencode " +(HTTP) This posts data, similar to the other --data options with the exception +that this will do partial URL encoding. (Added in 7.17.2) + +The part should be using one of the two following syntaxes: +.RS +.IP "name=content" +This will make curl URL encode the content part and pass that on. Note that +the name part is not encoded. +.IP "name@filename" +This will make curl load data from the given file, URL encode that data and +pass it on in the POST like \fIname=urlencoded-data\fP. Note that the name +part is not encoded. +.RE .IP "--digest" (HTTP) Enables HTTP Digest authentication. This is a authentication that prevents the password from being sent over the wire in clear text. Use this in diff --git a/src/main.c b/src/main.c index d1b7009b7..d0bbdcdd7 100644 --- a/src/main.c +++ b/src/main.c @@ -357,6 +357,7 @@ struct OutStruct { }; struct Configurable { + CURL *easy; /* once we have one, we keep it here */ bool remote_time; char *random_file; char *egd_file; @@ -619,6 +620,7 @@ static void help(void) " -d/--data HTTP POST data (H)", " --data-ascii HTTP POST ASCII data (H)", " --data-binary HTTP POST binary data (H)", + " --data-urlencode HTTP POST data url encoded (H)", " --negotiate Use HTTP Negotiate Authentication (H)", " --digest Use HTTP Digest Authentication (H)", " --disable-eprt Inhibit using EPRT or LPRT (F)", @@ -1532,6 +1534,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */ {"d", "data", TRUE}, {"da", "data-ascii", TRUE}, {"db", "data-binary", TRUE}, + {"de", "data-urlencode", TRUE}, {"D", "dump-header", TRUE}, {"e", "referer", TRUE}, {"E", "cert", TRUE}, @@ -2045,12 +2048,83 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */ /* postfield data */ { char *postdata=NULL; + FILE *file; - if('@' == *nextarg) { + if(subletter == 'e') { /* --data-urlencode*/ + /* [name]=[content], we encode the content part only + * [name]@[file name] + * + * Case 2: we first load the file using that name and then encode + * the content. + */ + char *p = strchr(nextarg, '='); + long size = 0; + size_t nlen; + if(!p) + p = strchr(nextarg, '@'); + if(!p) { + warnf(config, "bad use of --data-urlencode\n"); + return PARAM_BAD_USE; + } + nlen = p - nextarg; /* length of the name part */ + if('@' == *p) { + /* a '@' letter, it means that a file name or - (stdin) follows */ + + p++; /* pass the separator */ + + if(curlx_strequal("-", p)) { + file = stdin; + SET_BINMODE(stdin); + } + else { + file = fopen(p, "rb"); + if(!file) + warnf(config, + "Couldn't read data from file \"%s\", this makes " + "an empty POST.\n", nextarg); + } + + postdata = file2memory(file, &size); + + if(file && (file != stdin)) + fclose(file); + } + else { + GetStr(&postdata, ++p); + size = strlen(postdata); + } + + if(!postdata) { + /* no data from the file, point to a zero byte string to make this + get sent as a POST anyway */ + postdata=strdup(""); + } + else { + char *enc = curl_easy_escape(config->easy, postdata, size); + if(enc) { + /* now make a string with the name from above and append the + encoded string */ + size_t outlen = nlen + strlen(enc) + 2; + char *n = malloc(outlen); + if(!n) + return PARAM_NO_MEM; + + snprintf(n, outlen, "%.*s=%s", nlen, nextarg, enc); + curl_free(enc); + free(postdata); + if(n) { + postdata = n; + } + else + return PARAM_NO_MEM; + } + else + return PARAM_NO_MEM; + } + } + else if('@' == *nextarg) { /* the data begins with a '@' letter, it means that a file name or - (stdin) follows */ - FILE *file; - nextarg++; /* pass the @ */ if(curlx_strequal("-", nextarg)) { @@ -3334,6 +3408,9 @@ static void free_config_fields(struct Configurable *config) curl_slist_free_all(config->postquote); curl_slist_free_all(config->headers); curl_slist_free_all(config->telnet_options); + + if(config->easy) + curl_easy_cleanup(config->easy); } #ifdef WIN32 @@ -3443,9 +3520,9 @@ CURLcode _my_setopt(CURL *curl, struct Configurable *config, const char *name, if(config->libcurl) { /* we only use this for real if --libcurl was used */ - bufp = curl_maprintf("%scurl_easy_setopt(hnd, %s, %s);%s", - remark?"/* ":"", name, value, - remark?" [REMARK] */":""); + bufp = curlx_maprintf("%scurl_easy_setopt(hnd, %s, %s);%s", + remark?"/* ":"", name, value, + remark?" [REMARK] */":""); if (!bufp || !curl_slist_append(easycode, bufp)) ret = CURLE_OUT_OF_MEMORY; @@ -3577,6 +3654,17 @@ operate(struct Configurable *config, int argc, argv_item_t argv[]) } #endif + /* + * Get a curl handle to use for all forthcoming curl transfers. Cleanup + * when all transfers are done. + */ + curl = curl_easy_init(); + if(!curl) { + clean_getout(config); + return CURLE_FAILED_INIT; + } + config->easy = curl; + memset(&outs,0,sizeof(outs)); config->outs = &outs; @@ -3733,16 +3821,6 @@ operate(struct Configurable *config, int argc, argv_item_t argv[]) } } - /* - * Get a curl handle to use for all forthcoming curl transfers. Cleanup - * when all transfers are done. - */ - curl = curl_easy_init(); - if(!curl) { - clean_getout(config); - return CURLE_FAILED_INIT; - } - /* This is the first entry added to easycode and it initializes the slist */ easycode = curl_slist_append(easycode, "CURL *hnd = curl_easy_init();"); if(!easycode) { @@ -4663,6 +4741,7 @@ quit_curl: /* cleanup the curl handle! */ curl_easy_cleanup(curl); + config->easy = NULL; /* cleanup now */ if (easycode) curl_slist_append(easycode, "curl_easy_cleanup(hnd);");