From 0435800f65ce3eddd11ad6d6877d4d0818bfcaa6 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Mon, 3 Oct 2011 22:59:38 +0200 Subject: curl tool: reviewed code moved to tool_*.[ch] files --- src/tool_formparse.c | 321 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 321 insertions(+) create mode 100644 src/tool_formparse.c (limited to 'src/tool_formparse.c') diff --git a/src/tool_formparse.c b/src/tool_formparse.c new file mode 100644 index 000000000..5d6263e5c --- /dev/null +++ b/src/tool_formparse.c @@ -0,0 +1,321 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, 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 + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "setup.h" + +#include + +#include "rawstr.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_mfiles.h" +#include "tool_msgs.h" +#include "tool_formparse.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/*************************************************************************** + * + * formparse() + * + * Reads a 'name=value' parameter and builds the appropriate linked list. + * + * Specify files to upload with 'name=@filename'. Supports specified + * given Content-Type of the files. Such as ';type='. + * + * If literal_value is set, any initial '@' or '<' in the value string + * loses its special meaning, as does any embedded ';type='. + * + * You may specify more than one file for a single name (field). Specify + * multiple files by writing it like: + * + * 'name=@filename,filename2,filename3' + * + * If you want content-types specified for each too, write them like: + * + * 'name=@filename;type=image/gif,filename2,filename3' + * + * If you want custom headers added for a single part, write them in a separate + * file and do like this: + * + * 'name=foo;headers=@headerfile' or why not + * 'name=@filemame;headers=@headerfile' + * + * To upload a file, but to fake the file name that will be included in the + * formpost, do like this: + * + * 'name=@filename;filename=/dev/null' + * + * This function uses curl_formadd to fulfill it's job. Is heavily based on + * the old curl_formparse code. + * + ***************************************************************************/ + +#define FORM_FILE_SEPARATOR ',' +#define FORM_TYPE_SEPARATOR ';' + +int formparse(struct Configurable *config, + const char *input, + struct curl_httppost **httppost, + struct curl_httppost **last_post, + bool literal_value) +{ + /* nextarg MUST be a string in the format 'name=contents' and we'll + build a linked list with the info */ + char name[256]; + char *contents = NULL; + char major[128]; + char minor[128]; + char *contp; + const char *type = NULL; + char *sep; + char *sep2; + + if((1 == sscanf(input, "%255[^=]=", name)) && + ((contp = strchr(input, '=')) != NULL)) { + /* the input was using the correct format */ + + /* Allocate the contents */ + contents = strdup(contp+1); + if(!contents) { + fprintf(config->errors, "out of memory\n"); + return 1; + } + contp = contents; + + if('@' == contp[0] && !literal_value) { + + /* we use the @-letter to indicate file name(s) */ + + struct multi_files *multi_start = NULL; + struct multi_files *multi_current = NULL; + + contp++; + + do { + /* since this was a file, it may have a content-type specifier + at the end too, or a filename. Or both. */ + char *ptr; + char *filename = NULL; + + sep = strchr(contp, FORM_TYPE_SEPARATOR); + sep2 = strchr(contp, FORM_FILE_SEPARATOR); + + /* pick the closest */ + if(sep2 && (sep2 < sep)) { + sep = sep2; + + /* no type was specified! */ + } + + type = NULL; + + if(sep) { + + /* if we got here on a comma, don't do much */ + if(FORM_FILE_SEPARATOR == *sep) + ptr = NULL; + else + ptr = sep+1; + + *sep = '\0'; /* terminate file name at separator */ + + while(ptr && (FORM_FILE_SEPARATOR!= *ptr)) { + + /* pass all white spaces */ + while(ISSPACE(*ptr)) + ptr++; + + if(checkprefix("type=", ptr)) { + /* set type pointer */ + type = &ptr[5]; + + /* verify that this is a fine type specifier */ + if(2 != sscanf(type, "%127[^/]/%127[^;,\n]", + major, minor)) { + warnf(config, "Illegally formatted content-type field!\n"); + Curl_safefree(contents); + FreeMultiInfo(&multi_start, &multi_current); + return 2; /* illegal content-type syntax! */ + } + + /* now point beyond the content-type specifier */ + sep = (char *)type + strlen(major)+strlen(minor)+1; + + /* there's a semicolon following - we check if it is a filename + specified and if not we simply assume that it is text that + the user wants included in the type and include that too up + to the next zero or semicolon. */ + if((*sep==';') && !checkprefix(";filename=", sep)) { + sep2 = strchr(sep+1, ';'); + if(sep2) + sep = sep2; + else + sep = sep + strlen(sep); /* point to end of string */ + } + + if(*sep) { + *sep = '\0'; /* zero terminate type string */ + + ptr = sep+1; + } + else + ptr = NULL; /* end */ + } + else if(checkprefix("filename=", ptr)) { + filename = &ptr[9]; + ptr = strchr(filename, FORM_TYPE_SEPARATOR); + if(!ptr) { + ptr = strchr(filename, FORM_FILE_SEPARATOR); + } + if(ptr) { + *ptr = '\0'; /* zero terminate */ + ptr++; + } + } + else + /* confusion, bail out of loop */ + break; + } + /* find the following comma */ + if(ptr) + sep = strchr(ptr, FORM_FILE_SEPARATOR); + else + sep = NULL; + } + else { + sep = strchr(contp, FORM_FILE_SEPARATOR); + } + if(sep) { + /* the next file name starts here */ + *sep = '\0'; + sep++; + } + /* if type == NULL curl_formadd takes care of the problem */ + + if(!AddMultiFiles(contp, type, filename, &multi_start, + &multi_current)) { + warnf(config, "Error building form post!\n"); + Curl_safefree(contents); + FreeMultiInfo(&multi_start, &multi_current); + return 3; + } + contp = sep; /* move the contents pointer to after the separator */ + + } while(sep && *sep); /* loop if there's another file name */ + + /* now we add the multiple files section */ + if(multi_start) { + struct curl_forms *forms = NULL; + struct multi_files *ptr = multi_start; + unsigned int i, count = 0; + while(ptr) { + ptr = ptr->next; + ++count; + } + forms = malloc((count+1)*sizeof(struct curl_forms)); + if(!forms) { + fprintf(config->errors, "Error building form post!\n"); + Curl_safefree(contents); + FreeMultiInfo(&multi_start, &multi_current); + return 4; + } + for(i = 0, ptr = multi_start; i < count; ++i, ptr = ptr->next) { + forms[i].option = ptr->form.option; + forms[i].value = ptr->form.value; + } + forms[count].option = CURLFORM_END; + FreeMultiInfo(&multi_start, &multi_current); + if(curl_formadd(httppost, last_post, + CURLFORM_COPYNAME, name, + CURLFORM_ARRAY, forms, CURLFORM_END) != 0) { + warnf(config, "curl_formadd failed!\n"); + Curl_safefree(forms); + Curl_safefree(contents); + return 5; + } + Curl_safefree(forms); + } + } + else { + struct curl_forms info[4]; + int i = 0; + char *ct = literal_value ? NULL : strstr(contp, ";type="); + + info[i].option = CURLFORM_COPYNAME; + info[i].value = name; + i++; + + if(ct) { + info[i].option = CURLFORM_CONTENTTYPE; + info[i].value = &ct[6]; + i++; + ct[0] = '\0'; /* zero terminate here */ + } + + if(contp[0]=='<' && !literal_value) { + info[i].option = CURLFORM_FILECONTENT; + info[i].value = contp+1; + i++; + info[i].option = CURLFORM_END; + + if(curl_formadd(httppost, last_post, + CURLFORM_ARRAY, info, CURLFORM_END ) != 0) { + warnf(config, "curl_formadd failed, possibly the file %s is bad!\n", + contp+1); + Curl_safefree(contents); + return 6; + } + } + else { +#ifdef CURL_DOES_CONVERSIONS + if(convert_to_network(contp, strlen(contp))) { + warnf(config, "curl_formadd failed!\n"); + Curl_safefree(contents); + return 7; + } +#endif + info[i].option = CURLFORM_COPYCONTENTS; + info[i].value = contp; + i++; + info[i].option = CURLFORM_END; + if(curl_formadd(httppost, last_post, + CURLFORM_ARRAY, info, CURLFORM_END) != 0) { + warnf(config, "curl_formadd failed!\n"); + Curl_safefree(contents); + return 8; + } + } + } + + } + else { + warnf(config, "Illegally formatted input field!\n"); + return 1; + } + Curl_safefree(contents); + return 0; +} + -- cgit v1.2.1 From 7b8590d1f5bc332ad49300c698a7992939eb05a9 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 16 Dec 2011 11:43:25 +0100 Subject: curl -F: fix multiple file upload with custom type Test case 1315 was added to verify this functionality. When passing in multiple files to a single -F, the parser would get all confused if one of the specified files had a custom type= assigned. Reported by: Colin Hogben --- src/tool_formparse.c | 54 ++++++++++++++++++++-------------------------------- 1 file changed, 21 insertions(+), 33 deletions(-) (limited to 'src/tool_formparse.c') diff --git a/src/tool_formparse.c b/src/tool_formparse.c index 5d6263e5c..ff2210ac8 100644 --- a/src/tool_formparse.c +++ b/src/tool_formparse.c @@ -73,9 +73,6 @@ * ***************************************************************************/ -#define FORM_FILE_SEPARATOR ',' -#define FORM_TYPE_SEPARATOR ';' - int formparse(struct Configurable *config, const char *input, struct curl_httppost **httppost, @@ -120,8 +117,8 @@ int formparse(struct Configurable *config, char *ptr; char *filename = NULL; - sep = strchr(contp, FORM_TYPE_SEPARATOR); - sep2 = strchr(contp, FORM_FILE_SEPARATOR); + sep = strchr(contp, ';'); + sep2 = strchr(contp, ','); /* pick the closest */ if(sep2 && (sep2 < sep)) { @@ -133,16 +130,13 @@ int formparse(struct Configurable *config, type = NULL; if(sep) { - - /* if we got here on a comma, don't do much */ - if(FORM_FILE_SEPARATOR == *sep) - ptr = NULL; - else - ptr = sep+1; + bool semicolon = (';' == *sep); *sep = '\0'; /* terminate file name at separator */ - while(ptr && (FORM_FILE_SEPARATOR!= *ptr)) { + ptr = sep+1; /* point to the text following the separator */ + + while(semicolon && ptr && (','!= *ptr)) { /* pass all white spaces */ while(ISSPACE(*ptr)) @@ -168,13 +162,17 @@ int formparse(struct Configurable *config, specified and if not we simply assume that it is text that the user wants included in the type and include that too up to the next zero or semicolon. */ - if((*sep==';') && !checkprefix(";filename=", sep)) { - sep2 = strchr(sep+1, ';'); - if(sep2) - sep = sep2; - else - sep = sep + strlen(sep); /* point to end of string */ + if(*sep==';') { + if(!checkprefix(";filename=", sep)) { + sep2 = strchr(sep+1, ';'); + if(sep2) + sep = sep2; + else + sep = sep + strlen(sep); /* point to end of string */ + } } + else + semicolon = FALSE; if(*sep) { *sep = '\0'; /* zero terminate type string */ @@ -186,9 +184,9 @@ int formparse(struct Configurable *config, } else if(checkprefix("filename=", ptr)) { filename = &ptr[9]; - ptr = strchr(filename, FORM_TYPE_SEPARATOR); + ptr = strchr(filename, ';'); if(!ptr) { - ptr = strchr(filename, FORM_FILE_SEPARATOR); + ptr = strchr(filename, ','); } if(ptr) { *ptr = '\0'; /* zero terminate */ @@ -199,20 +197,10 @@ int formparse(struct Configurable *config, /* confusion, bail out of loop */ break; } - /* find the following comma */ - if(ptr) - sep = strchr(ptr, FORM_FILE_SEPARATOR); - else - sep = NULL; - } - else { - sep = strchr(contp, FORM_FILE_SEPARATOR); - } - if(sep) { - /* the next file name starts here */ - *sep = '\0'; - sep++; + + sep = ptr; } + /* if type == NULL curl_formadd takes care of the problem */ if(!AddMultiFiles(contp, type, filename, &multi_start, -- cgit v1.2.1 From 3a55daee3df6b9d1d613a8390d6b1f67ccee9b05 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Mon, 2 Jan 2012 19:31:02 +0100 Subject: tool_formparse.c: fix compiler warning: enumerated type mixed with another type --- src/tool_formparse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/tool_formparse.c') diff --git a/src/tool_formparse.c b/src/tool_formparse.c index ff2210ac8..248c89ce7 100644 --- a/src/tool_formparse.c +++ b/src/tool_formparse.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2012, 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 @@ -130,7 +130,7 @@ int formparse(struct Configurable *config, type = NULL; if(sep) { - bool semicolon = (';' == *sep); + bool semicolon = (';' == *sep) ? TRUE : FALSE; *sep = '\0'; /* terminate file name at separator */ -- cgit v1.2.1 From 919c97fa65a5c00f7044e849eeb0095408413505 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Fri, 6 Apr 2012 23:35:15 +0200 Subject: curl tool: use configuration files from lib directory Configuration files such as curl_config.h and all config-*.h no longer exist nor are generated/copied into 'src' directory, now these only exist in 'lib' directory from where curl tool sources uses them. Additionally old src/setup.h has been refactored into src/tool_setup.h which now pulls lib/setup.h The possibility of a makefile needing an include path adjustment exists. --- src/tool_formparse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/tool_formparse.c') diff --git a/src/tool_formparse.c b/src/tool_formparse.c index 248c89ce7..14003e7cc 100644 --- a/src/tool_formparse.c +++ b/src/tool_formparse.c @@ -19,7 +19,7 @@ * KIND, either express or implied. * ***************************************************************************/ -#include "setup.h" +#include "tool_setup.h" #include -- cgit v1.2.1 From 01b0f1061da2bd7a8703f4c8aa846a9088d7ab3e Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Sun, 8 Apr 2012 13:50:18 +0200 Subject: curl tool: make curl.h first header included in tool_setup.h --- src/tool_formparse.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/tool_formparse.c') diff --git a/src/tool_formparse.c b/src/tool_formparse.c index 14003e7cc..e83f7eda1 100644 --- a/src/tool_formparse.c +++ b/src/tool_formparse.c @@ -21,8 +21,6 @@ ***************************************************************************/ #include "tool_setup.h" -#include - #include "rawstr.h" #define ENABLE_CURLX_PRINTF -- cgit v1.2.1 From 51114f07f177a2b59a5060c9699daf925f2269a6 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Thu, 12 Apr 2012 19:28:46 +0200 Subject: tool_formparse.c: rename a couple of vars to avoid declaration shadowing --- src/tool_formparse.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/tool_formparse.c') diff --git a/src/tool_formparse.c b/src/tool_formparse.c index e83f7eda1..12b1a9d46 100644 --- a/src/tool_formparse.c +++ b/src/tool_formparse.c @@ -81,8 +81,8 @@ int formparse(struct Configurable *config, build a linked list with the info */ char name[256]; char *contents = NULL; - char major[128]; - char minor[128]; + char type_major[128]; + char type_minor[128]; char *contp; const char *type = NULL; char *sep; @@ -146,7 +146,7 @@ int formparse(struct Configurable *config, /* verify that this is a fine type specifier */ if(2 != sscanf(type, "%127[^/]/%127[^;,\n]", - major, minor)) { + type_major, type_minor)) { warnf(config, "Illegally formatted content-type field!\n"); Curl_safefree(contents); FreeMultiInfo(&multi_start, &multi_current); @@ -154,7 +154,7 @@ int formparse(struct Configurable *config, } /* now point beyond the content-type specifier */ - sep = (char *)type + strlen(major)+strlen(minor)+1; + sep = (char *)type + strlen(type_major)+strlen(type_minor)+1; /* there's a semicolon following - we check if it is a filename specified and if not we simply assume that it is text that -- cgit v1.2.1