Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * _ _ ____ _ |
| 3 | * Project ___| | | | _ \| | |
| 4 | * / __| | | | |_) | | |
| 5 | * | (__| |_| | _ <| |___ |
| 6 | * \___|\___/|_| \_\_____| |
| 7 | * |
Elliott Hughes | cac3980 | 2018-04-27 16:19:43 -0700 | [diff] [blame] | 8 | * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 9 | * |
| 10 | * This software is licensed as described in the file COPYING, which |
| 11 | * you should have received as part of this distribution. The terms |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 12 | * are also available at https://curl.haxx.se/docs/copyright.html. |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 13 | * |
| 14 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell |
| 15 | * copies of the Software, and permit persons to whom the Software is |
| 16 | * furnished to do so, under the terms of the COPYING file. |
| 17 | * |
| 18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 19 | * KIND, either express or implied. |
| 20 | * |
| 21 | ***************************************************************************/ |
| 22 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 23 | #include "curl_setup.h" |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 24 | |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 25 | #include <curl/curl.h> |
| 26 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 27 | #ifndef CURL_DISABLE_HTTP |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 28 | |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 29 | #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) |
| 30 | #include <libgen.h> |
| 31 | #endif |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 32 | |
Alex Deymo | e3149cc | 2016-10-05 11:18:42 -0700 | [diff] [blame] | 33 | #include "urldata.h" /* for struct Curl_easy */ |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 34 | #include "formdata.h" |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 35 | #include "mime.h" |
| 36 | #include "non-ascii.h" |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 37 | #include "vtls/vtls.h" |
Elliott Hughes | cee0338 | 2017-06-23 12:17:18 -0700 | [diff] [blame] | 38 | #include "strcase.h" |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 39 | #include "sendf.h" |
| 40 | #include "strdup.h" |
Elliott Hughes | cee0338 | 2017-06-23 12:17:18 -0700 | [diff] [blame] | 41 | #include "rand.h" |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 42 | /* The last 3 #include files should be in this order */ |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 43 | #include "curl_printf.h" |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 44 | #include "curl_memory.h" |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 45 | #include "memdebug.h" |
| 46 | |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 47 | |
| 48 | /* What kind of Content-Type to use on un-specified files with unrecognized |
| 49 | extensions. */ |
| 50 | #define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream" |
| 51 | |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 52 | #define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME |
| 53 | #define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME |
| 54 | #define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS |
| 55 | #define HTTPPOST_READFILE CURL_HTTPPOST_READFILE |
| 56 | #define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER |
| 57 | #define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK |
| 58 | #define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER |
| 59 | |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 60 | /*************************************************************************** |
| 61 | * |
| 62 | * AddHttpPost() |
| 63 | * |
| 64 | * Adds a HttpPost structure to the list, if parent_post is given becomes |
| 65 | * a subpost of parent_post instead of a direct list element. |
| 66 | * |
| 67 | * Returns newly allocated HttpPost on success and NULL if malloc failed. |
| 68 | * |
| 69 | ***************************************************************************/ |
| 70 | static struct curl_httppost * |
| 71 | AddHttpPost(char *name, size_t namelength, |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 72 | char *value, curl_off_t contentslength, |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 73 | char *buffer, size_t bufferlength, |
| 74 | char *contenttype, |
| 75 | long flags, |
Elliott Hughes | cee0338 | 2017-06-23 12:17:18 -0700 | [diff] [blame] | 76 | struct curl_slist *contentHeader, |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 77 | char *showfilename, char *userp, |
| 78 | struct curl_httppost *parent_post, |
| 79 | struct curl_httppost **httppost, |
| 80 | struct curl_httppost **last_post) |
| 81 | { |
| 82 | struct curl_httppost *post; |
| 83 | post = calloc(1, sizeof(struct curl_httppost)); |
| 84 | if(post) { |
| 85 | post->name = name; |
| 86 | post->namelength = (long)(name?(namelength?namelength:strlen(name)):0); |
| 87 | post->contents = value; |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 88 | post->contentlen = contentslength; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 89 | post->buffer = buffer; |
| 90 | post->bufferlength = (long)bufferlength; |
| 91 | post->contenttype = contenttype; |
| 92 | post->contentheader = contentHeader; |
| 93 | post->showfilename = showfilename; |
Elliott Hughes | 82be86d | 2017-09-20 17:00:17 -0700 | [diff] [blame] | 94 | post->userp = userp; |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 95 | post->flags = flags | CURL_HTTPPOST_LARGE; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 96 | } |
| 97 | else |
| 98 | return NULL; |
| 99 | |
| 100 | if(parent_post) { |
| 101 | /* now, point our 'more' to the original 'more' */ |
| 102 | post->more = parent_post->more; |
| 103 | |
| 104 | /* then move the original 'more' to point to ourselves */ |
| 105 | parent_post->more = post; |
| 106 | } |
| 107 | else { |
| 108 | /* make the previous point to this */ |
| 109 | if(*last_post) |
| 110 | (*last_post)->next = post; |
| 111 | else |
| 112 | (*httppost) = post; |
| 113 | |
| 114 | (*last_post) = post; |
| 115 | } |
| 116 | return post; |
| 117 | } |
| 118 | |
| 119 | /*************************************************************************** |
| 120 | * |
| 121 | * AddFormInfo() |
| 122 | * |
| 123 | * Adds a FormInfo structure to the list presented by parent_form_info. |
| 124 | * |
| 125 | * Returns newly allocated FormInfo on success and NULL if malloc failed/ |
| 126 | * parent_form_info is NULL. |
| 127 | * |
| 128 | ***************************************************************************/ |
| 129 | static FormInfo * AddFormInfo(char *value, |
| 130 | char *contenttype, |
| 131 | FormInfo *parent_form_info) |
| 132 | { |
| 133 | FormInfo *form_info; |
| 134 | form_info = calloc(1, sizeof(struct FormInfo)); |
| 135 | if(form_info) { |
| 136 | if(value) |
| 137 | form_info->value = value; |
| 138 | if(contenttype) |
| 139 | form_info->contenttype = contenttype; |
| 140 | form_info->flags = HTTPPOST_FILENAME; |
| 141 | } |
| 142 | else |
| 143 | return NULL; |
| 144 | |
| 145 | if(parent_form_info) { |
| 146 | /* now, point our 'more' to the original 'more' */ |
| 147 | form_info->more = parent_form_info->more; |
| 148 | |
| 149 | /* then move the original 'more' to point to ourselves */ |
| 150 | parent_form_info->more = form_info; |
| 151 | } |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 152 | |
| 153 | return form_info; |
| 154 | } |
| 155 | |
| 156 | /*************************************************************************** |
| 157 | * |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 158 | * FormAdd() |
| 159 | * |
| 160 | * Stores a formpost parameter and builds the appropriate linked list. |
| 161 | * |
| 162 | * Has two principal functionalities: using files and byte arrays as |
| 163 | * post parts. Byte arrays are either copied or just the pointer is stored |
| 164 | * (as the user requests) while for files only the filename and not the |
| 165 | * content is stored. |
| 166 | * |
| 167 | * While you may have only one byte array for each name, multiple filenames |
| 168 | * are allowed (and because of this feature CURLFORM_END is needed after |
| 169 | * using CURLFORM_FILE). |
| 170 | * |
| 171 | * Examples: |
| 172 | * |
| 173 | * Simple name/value pair with copied contents: |
| 174 | * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", |
| 175 | * CURLFORM_COPYCONTENTS, "value", CURLFORM_END); |
| 176 | * |
| 177 | * name/value pair where only the content pointer is remembered: |
| 178 | * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", |
| 179 | * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END); |
| 180 | * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used) |
| 181 | * |
| 182 | * storing a filename (CONTENTTYPE is optional!): |
| 183 | * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", |
| 184 | * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text", |
| 185 | * CURLFORM_END); |
| 186 | * |
| 187 | * storing multiple filenames: |
| 188 | * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", |
| 189 | * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END); |
| 190 | * |
| 191 | * Returns: |
| 192 | * CURL_FORMADD_OK on success |
| 193 | * CURL_FORMADD_MEMORY if the FormInfo allocation fails |
| 194 | * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form |
| 195 | * CURL_FORMADD_NULL if a null pointer was given for a char |
| 196 | * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed |
| 197 | * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 198 | * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 199 | * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated |
| 200 | * CURL_FORMADD_MEMORY if some allocation for string copying failed. |
| 201 | * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array |
| 202 | * |
| 203 | ***************************************************************************/ |
| 204 | |
| 205 | static |
| 206 | CURLFORMcode FormAdd(struct curl_httppost **httppost, |
| 207 | struct curl_httppost **last_post, |
| 208 | va_list params) |
| 209 | { |
| 210 | FormInfo *first_form, *current_form, *form = NULL; |
| 211 | CURLFORMcode return_value = CURL_FORMADD_OK; |
| 212 | const char *prevtype = NULL; |
| 213 | struct curl_httppost *post = NULL; |
| 214 | CURLformoption option; |
| 215 | struct curl_forms *forms = NULL; |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 216 | char *array_value = NULL; /* value read from an array */ |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 217 | |
| 218 | /* This is a state variable, that if TRUE means that we're parsing an |
| 219 | array that we got passed to us. If FALSE we're parsing the input |
| 220 | va_list arguments. */ |
| 221 | bool array_state = FALSE; |
| 222 | |
| 223 | /* |
| 224 | * We need to allocate the first struct to fill in. |
| 225 | */ |
| 226 | first_form = calloc(1, sizeof(struct FormInfo)); |
| 227 | if(!first_form) |
| 228 | return CURL_FORMADD_MEMORY; |
| 229 | |
| 230 | current_form = first_form; |
| 231 | |
| 232 | /* |
| 233 | * Loop through all the options set. Break if we have an error to report. |
| 234 | */ |
| 235 | while(return_value == CURL_FORMADD_OK) { |
| 236 | |
| 237 | /* first see if we have more parts of the array param */ |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 238 | if(array_state && forms) { |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 239 | /* get the upcoming option from the given array */ |
| 240 | option = forms->option; |
| 241 | array_value = (char *)forms->value; |
| 242 | |
| 243 | forms++; /* advance this to next entry */ |
| 244 | if(CURLFORM_END == option) { |
| 245 | /* end of array state */ |
| 246 | array_state = FALSE; |
| 247 | continue; |
| 248 | } |
| 249 | } |
| 250 | else { |
| 251 | /* This is not array-state, get next option */ |
| 252 | option = va_arg(params, CURLformoption); |
| 253 | if(CURLFORM_END == option) |
| 254 | break; |
| 255 | } |
| 256 | |
Elliott Hughes | 82be86d | 2017-09-20 17:00:17 -0700 | [diff] [blame] | 257 | switch(option) { |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 258 | case CURLFORM_ARRAY: |
| 259 | if(array_state) |
| 260 | /* we don't support an array from within an array */ |
| 261 | return_value = CURL_FORMADD_ILLEGAL_ARRAY; |
| 262 | else { |
| 263 | forms = va_arg(params, struct curl_forms *); |
| 264 | if(forms) |
| 265 | array_state = TRUE; |
| 266 | else |
| 267 | return_value = CURL_FORMADD_NULL; |
| 268 | } |
| 269 | break; |
| 270 | |
| 271 | /* |
| 272 | * Set the Name property. |
| 273 | */ |
| 274 | case CURLFORM_PTRNAME: |
| 275 | #ifdef CURL_DOES_CONVERSIONS |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 276 | /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy |
| 277 | * the data in all cases so that we'll have safe memory for the eventual |
| 278 | * conversion. |
| 279 | */ |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 280 | #else |
| 281 | current_form->flags |= HTTPPOST_PTRNAME; /* fall through */ |
| 282 | #endif |
Elliott Hughes | 82be86d | 2017-09-20 17:00:17 -0700 | [diff] [blame] | 283 | /* FALLTHROUGH */ |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 284 | case CURLFORM_COPYNAME: |
| 285 | if(current_form->name) |
| 286 | return_value = CURL_FORMADD_OPTION_TWICE; |
| 287 | else { |
| 288 | char *name = array_state? |
| 289 | array_value:va_arg(params, char *); |
| 290 | if(name) |
| 291 | current_form->name = name; /* store for the moment */ |
| 292 | else |
| 293 | return_value = CURL_FORMADD_NULL; |
| 294 | } |
| 295 | break; |
| 296 | case CURLFORM_NAMELENGTH: |
| 297 | if(current_form->namelength) |
| 298 | return_value = CURL_FORMADD_OPTION_TWICE; |
| 299 | else |
| 300 | current_form->namelength = |
| 301 | array_state?(size_t)array_value:(size_t)va_arg(params, long); |
| 302 | break; |
| 303 | |
| 304 | /* |
| 305 | * Set the contents property. |
| 306 | */ |
| 307 | case CURLFORM_PTRCONTENTS: |
| 308 | current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */ |
| 309 | case CURLFORM_COPYCONTENTS: |
| 310 | if(current_form->value) |
| 311 | return_value = CURL_FORMADD_OPTION_TWICE; |
| 312 | else { |
| 313 | char *value = |
| 314 | array_state?array_value:va_arg(params, char *); |
| 315 | if(value) |
| 316 | current_form->value = value; /* store for the moment */ |
| 317 | else |
| 318 | return_value = CURL_FORMADD_NULL; |
| 319 | } |
| 320 | break; |
| 321 | case CURLFORM_CONTENTSLENGTH: |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 322 | current_form->contentslength = |
| 323 | array_state?(size_t)array_value:(size_t)va_arg(params, long); |
| 324 | break; |
| 325 | |
| 326 | case CURLFORM_CONTENTLEN: |
| 327 | current_form->flags |= CURL_HTTPPOST_LARGE; |
| 328 | current_form->contentslength = |
| 329 | array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t); |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 330 | break; |
| 331 | |
| 332 | /* Get contents from a given file name */ |
| 333 | case CURLFORM_FILECONTENT: |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 334 | if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE)) |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 335 | return_value = CURL_FORMADD_OPTION_TWICE; |
| 336 | else { |
| 337 | const char *filename = array_state? |
| 338 | array_value:va_arg(params, char *); |
| 339 | if(filename) { |
| 340 | current_form->value = strdup(filename); |
| 341 | if(!current_form->value) |
| 342 | return_value = CURL_FORMADD_MEMORY; |
| 343 | else { |
| 344 | current_form->flags |= HTTPPOST_READFILE; |
| 345 | current_form->value_alloc = TRUE; |
| 346 | } |
| 347 | } |
| 348 | else |
| 349 | return_value = CURL_FORMADD_NULL; |
| 350 | } |
| 351 | break; |
| 352 | |
| 353 | /* We upload a file */ |
| 354 | case CURLFORM_FILE: |
| 355 | { |
| 356 | const char *filename = array_state?array_value: |
| 357 | va_arg(params, char *); |
| 358 | |
| 359 | if(current_form->value) { |
| 360 | if(current_form->flags & HTTPPOST_FILENAME) { |
| 361 | if(filename) { |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 362 | char *fname = strdup(filename); |
| 363 | if(!fname) |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 364 | return_value = CURL_FORMADD_MEMORY; |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 365 | else { |
| 366 | form = AddFormInfo(fname, NULL, current_form); |
| 367 | if(!form) { |
| 368 | free(fname); |
| 369 | return_value = CURL_FORMADD_MEMORY; |
| 370 | } |
| 371 | else { |
| 372 | form->value_alloc = TRUE; |
| 373 | current_form = form; |
| 374 | form = NULL; |
| 375 | } |
| 376 | } |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 377 | } |
| 378 | else |
| 379 | return_value = CURL_FORMADD_NULL; |
| 380 | } |
| 381 | else |
| 382 | return_value = CURL_FORMADD_OPTION_TWICE; |
| 383 | } |
| 384 | else { |
| 385 | if(filename) { |
| 386 | current_form->value = strdup(filename); |
| 387 | if(!current_form->value) |
| 388 | return_value = CURL_FORMADD_MEMORY; |
| 389 | else { |
| 390 | current_form->flags |= HTTPPOST_FILENAME; |
| 391 | current_form->value_alloc = TRUE; |
| 392 | } |
| 393 | } |
| 394 | else |
| 395 | return_value = CURL_FORMADD_NULL; |
| 396 | } |
| 397 | break; |
| 398 | } |
| 399 | |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 400 | case CURLFORM_BUFFERPTR: |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 401 | current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 402 | if(current_form->buffer) |
| 403 | return_value = CURL_FORMADD_OPTION_TWICE; |
| 404 | else { |
| 405 | char *buffer = |
| 406 | array_state?array_value:va_arg(params, char *); |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 407 | if(buffer) { |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 408 | current_form->buffer = buffer; /* store for the moment */ |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 409 | current_form->value = buffer; /* make it non-NULL to be accepted |
| 410 | as fine */ |
| 411 | } |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 412 | else |
| 413 | return_value = CURL_FORMADD_NULL; |
| 414 | } |
| 415 | break; |
| 416 | |
| 417 | case CURLFORM_BUFFERLENGTH: |
| 418 | if(current_form->bufferlength) |
| 419 | return_value = CURL_FORMADD_OPTION_TWICE; |
| 420 | else |
| 421 | current_form->bufferlength = |
| 422 | array_state?(size_t)array_value:(size_t)va_arg(params, long); |
| 423 | break; |
| 424 | |
| 425 | case CURLFORM_STREAM: |
| 426 | current_form->flags |= HTTPPOST_CALLBACK; |
| 427 | if(current_form->userp) |
| 428 | return_value = CURL_FORMADD_OPTION_TWICE; |
| 429 | else { |
| 430 | char *userp = |
| 431 | array_state?array_value:va_arg(params, char *); |
| 432 | if(userp) { |
| 433 | current_form->userp = userp; |
| 434 | current_form->value = userp; /* this isn't strictly true but we |
| 435 | derive a value from this later on |
| 436 | and we need this non-NULL to be |
| 437 | accepted as a fine form part */ |
| 438 | } |
| 439 | else |
| 440 | return_value = CURL_FORMADD_NULL; |
| 441 | } |
| 442 | break; |
| 443 | |
| 444 | case CURLFORM_CONTENTTYPE: |
| 445 | { |
| 446 | const char *contenttype = |
| 447 | array_state?array_value:va_arg(params, char *); |
| 448 | if(current_form->contenttype) { |
| 449 | if(current_form->flags & HTTPPOST_FILENAME) { |
| 450 | if(contenttype) { |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 451 | char *type = strdup(contenttype); |
| 452 | if(!type) |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 453 | return_value = CURL_FORMADD_MEMORY; |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 454 | else { |
| 455 | form = AddFormInfo(NULL, type, current_form); |
| 456 | if(!form) { |
| 457 | free(type); |
| 458 | return_value = CURL_FORMADD_MEMORY; |
| 459 | } |
| 460 | else { |
| 461 | form->contenttype_alloc = TRUE; |
| 462 | current_form = form; |
| 463 | form = NULL; |
| 464 | } |
| 465 | } |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 466 | } |
| 467 | else |
| 468 | return_value = CURL_FORMADD_NULL; |
| 469 | } |
| 470 | else |
| 471 | return_value = CURL_FORMADD_OPTION_TWICE; |
| 472 | } |
| 473 | else { |
| 474 | if(contenttype) { |
| 475 | current_form->contenttype = strdup(contenttype); |
| 476 | if(!current_form->contenttype) |
| 477 | return_value = CURL_FORMADD_MEMORY; |
| 478 | else |
| 479 | current_form->contenttype_alloc = TRUE; |
| 480 | } |
| 481 | else |
| 482 | return_value = CURL_FORMADD_NULL; |
| 483 | } |
| 484 | break; |
| 485 | } |
| 486 | case CURLFORM_CONTENTHEADER: |
| 487 | { |
| 488 | /* this "cast increases required alignment of target type" but |
| 489 | we consider it OK anyway */ |
Elliott Hughes | cee0338 | 2017-06-23 12:17:18 -0700 | [diff] [blame] | 490 | struct curl_slist *list = array_state? |
| 491 | (struct curl_slist *)(void *)array_value: |
| 492 | va_arg(params, struct curl_slist *); |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 493 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 494 | if(current_form->contentheader) |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 495 | return_value = CURL_FORMADD_OPTION_TWICE; |
| 496 | else |
| 497 | current_form->contentheader = list; |
| 498 | |
| 499 | break; |
| 500 | } |
| 501 | case CURLFORM_FILENAME: |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 502 | case CURLFORM_BUFFER: |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 503 | { |
| 504 | const char *filename = array_state?array_value: |
| 505 | va_arg(params, char *); |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 506 | if(current_form->showfilename) |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 507 | return_value = CURL_FORMADD_OPTION_TWICE; |
| 508 | else { |
| 509 | current_form->showfilename = strdup(filename); |
| 510 | if(!current_form->showfilename) |
| 511 | return_value = CURL_FORMADD_MEMORY; |
| 512 | else |
| 513 | current_form->showfilename_alloc = TRUE; |
| 514 | } |
| 515 | break; |
| 516 | } |
| 517 | default: |
| 518 | return_value = CURL_FORMADD_UNKNOWN_OPTION; |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 519 | break; |
| 520 | } |
| 521 | } |
| 522 | |
| 523 | if(CURL_FORMADD_OK != return_value) { |
| 524 | /* On error, free allocated fields for all nodes of the FormInfo linked |
| 525 | list without deallocating nodes. List nodes are deallocated later on */ |
| 526 | FormInfo *ptr; |
| 527 | for(ptr = first_form; ptr != NULL; ptr = ptr->more) { |
| 528 | if(ptr->name_alloc) { |
| 529 | Curl_safefree(ptr->name); |
| 530 | ptr->name_alloc = FALSE; |
| 531 | } |
| 532 | if(ptr->value_alloc) { |
| 533 | Curl_safefree(ptr->value); |
| 534 | ptr->value_alloc = FALSE; |
| 535 | } |
| 536 | if(ptr->contenttype_alloc) { |
| 537 | Curl_safefree(ptr->contenttype); |
| 538 | ptr->contenttype_alloc = FALSE; |
| 539 | } |
| 540 | if(ptr->showfilename_alloc) { |
| 541 | Curl_safefree(ptr->showfilename); |
| 542 | ptr->showfilename_alloc = FALSE; |
| 543 | } |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 544 | } |
| 545 | } |
| 546 | |
| 547 | if(CURL_FORMADD_OK == return_value) { |
| 548 | /* go through the list, check for completeness and if everything is |
| 549 | * alright add the HttpPost item otherwise set return_value accordingly */ |
| 550 | |
| 551 | post = NULL; |
| 552 | for(form = first_form; |
| 553 | form != NULL; |
| 554 | form = form->more) { |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 555 | if(((!form->name || !form->value) && !post) || |
| 556 | ( (form->contentslength) && |
| 557 | (form->flags & HTTPPOST_FILENAME) ) || |
| 558 | ( (form->flags & HTTPPOST_FILENAME) && |
| 559 | (form->flags & HTTPPOST_PTRCONTENTS) ) || |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 560 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 561 | ( (!form->buffer) && |
| 562 | (form->flags & HTTPPOST_BUFFER) && |
| 563 | (form->flags & HTTPPOST_PTRBUFFER) ) || |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 564 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 565 | ( (form->flags & HTTPPOST_READFILE) && |
| 566 | (form->flags & HTTPPOST_PTRCONTENTS) ) |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 567 | ) { |
| 568 | return_value = CURL_FORMADD_INCOMPLETE; |
| 569 | break; |
| 570 | } |
Elliott Hughes | 82be86d | 2017-09-20 17:00:17 -0700 | [diff] [blame] | 571 | if(((form->flags & HTTPPOST_FILENAME) || |
| 572 | (form->flags & HTTPPOST_BUFFER)) && |
| 573 | !form->contenttype) { |
| 574 | char *f = form->flags & HTTPPOST_BUFFER? |
| 575 | form->showfilename : form->value; |
Elliott Hughes | cac3980 | 2018-04-27 16:19:43 -0700 | [diff] [blame] | 576 | char const *type; |
| 577 | type = Curl_mime_contenttype(f); |
| 578 | if(!type) |
| 579 | type = prevtype; |
| 580 | if(!type) |
| 581 | type = FILE_CONTENTTYPE_DEFAULT; |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 582 | |
Elliott Hughes | 82be86d | 2017-09-20 17:00:17 -0700 | [diff] [blame] | 583 | /* our contenttype is missing */ |
Elliott Hughes | cac3980 | 2018-04-27 16:19:43 -0700 | [diff] [blame] | 584 | form->contenttype = strdup(type); |
Elliott Hughes | 82be86d | 2017-09-20 17:00:17 -0700 | [diff] [blame] | 585 | if(!form->contenttype) { |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 586 | return_value = CURL_FORMADD_MEMORY; |
| 587 | break; |
| 588 | } |
Elliott Hughes | 82be86d | 2017-09-20 17:00:17 -0700 | [diff] [blame] | 589 | form->contenttype_alloc = TRUE; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 590 | } |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 591 | if(form->name && form->namelength) { |
| 592 | /* Name should not contain nul bytes. */ |
| 593 | size_t i; |
| 594 | for(i = 0; i < form->namelength; i++) |
| 595 | if(!form->name[i]) { |
| 596 | return_value = CURL_FORMADD_NULL; |
| 597 | break; |
| 598 | } |
| 599 | if(return_value != CURL_FORMADD_OK) |
| 600 | break; |
| 601 | } |
Elliott Hughes | 82be86d | 2017-09-20 17:00:17 -0700 | [diff] [blame] | 602 | if(!(form->flags & HTTPPOST_PTRNAME) && |
| 603 | (form == first_form) ) { |
| 604 | /* Note that there's small risk that form->name is NULL here if the |
| 605 | app passed in a bad combo, so we better check for that first. */ |
| 606 | if(form->name) { |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 607 | /* copy name (without strdup; possibly not nul-terminated) */ |
Elliott Hughes | 82be86d | 2017-09-20 17:00:17 -0700 | [diff] [blame] | 608 | form->name = Curl_memdup(form->name, form->namelength? |
| 609 | form->namelength: |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 610 | strlen(form->name) + 1); |
Elliott Hughes | 82be86d | 2017-09-20 17:00:17 -0700 | [diff] [blame] | 611 | } |
| 612 | if(!form->name) { |
| 613 | return_value = CURL_FORMADD_MEMORY; |
| 614 | break; |
| 615 | } |
| 616 | form->name_alloc = TRUE; |
| 617 | } |
| 618 | if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE | |
| 619 | HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER | |
| 620 | HTTPPOST_CALLBACK)) && form->value) { |
| 621 | /* copy value (without strdup; possibly contains null characters) */ |
| 622 | size_t clen = (size_t) form->contentslength; |
| 623 | if(!clen) |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 624 | clen = strlen(form->value) + 1; |
Elliott Hughes | 82be86d | 2017-09-20 17:00:17 -0700 | [diff] [blame] | 625 | |
| 626 | form->value = Curl_memdup(form->value, clen); |
| 627 | |
| 628 | if(!form->value) { |
| 629 | return_value = CURL_FORMADD_MEMORY; |
| 630 | break; |
| 631 | } |
| 632 | form->value_alloc = TRUE; |
| 633 | } |
| 634 | post = AddHttpPost(form->name, form->namelength, |
| 635 | form->value, form->contentslength, |
| 636 | form->buffer, form->bufferlength, |
| 637 | form->contenttype, form->flags, |
| 638 | form->contentheader, form->showfilename, |
| 639 | form->userp, |
| 640 | post, httppost, |
| 641 | last_post); |
| 642 | |
| 643 | if(!post) { |
| 644 | return_value = CURL_FORMADD_MEMORY; |
| 645 | break; |
| 646 | } |
| 647 | |
| 648 | if(form->contenttype) |
| 649 | prevtype = form->contenttype; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 650 | } |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 651 | if(CURL_FORMADD_OK != return_value) { |
| 652 | /* On error, free allocated fields for nodes of the FormInfo linked |
| 653 | list which are not already owned by the httppost linked list |
| 654 | without deallocating nodes. List nodes are deallocated later on */ |
| 655 | FormInfo *ptr; |
| 656 | for(ptr = form; ptr != NULL; ptr = ptr->more) { |
| 657 | if(ptr->name_alloc) { |
| 658 | Curl_safefree(ptr->name); |
| 659 | ptr->name_alloc = FALSE; |
| 660 | } |
| 661 | if(ptr->value_alloc) { |
| 662 | Curl_safefree(ptr->value); |
| 663 | ptr->value_alloc = FALSE; |
| 664 | } |
| 665 | if(ptr->contenttype_alloc) { |
| 666 | Curl_safefree(ptr->contenttype); |
| 667 | ptr->contenttype_alloc = FALSE; |
| 668 | } |
| 669 | if(ptr->showfilename_alloc) { |
| 670 | Curl_safefree(ptr->showfilename); |
| 671 | ptr->showfilename_alloc = FALSE; |
| 672 | } |
| 673 | } |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 674 | } |
| 675 | } |
| 676 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 677 | /* Always deallocate FormInfo linked list nodes without touching node |
| 678 | fields given that these have either been deallocated or are owned |
| 679 | now by the httppost linked list */ |
| 680 | while(first_form) { |
| 681 | FormInfo *ptr = first_form->more; |
| 682 | free(first_form); |
| 683 | first_form = ptr; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 684 | } |
| 685 | |
| 686 | return return_value; |
| 687 | } |
| 688 | |
| 689 | /* |
| 690 | * curl_formadd() is a public API to add a section to the multipart formpost. |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 691 | * |
| 692 | * @unittest: 1308 |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 693 | */ |
| 694 | |
| 695 | CURLFORMcode curl_formadd(struct curl_httppost **httppost, |
| 696 | struct curl_httppost **last_post, |
| 697 | ...) |
| 698 | { |
| 699 | va_list arg; |
| 700 | CURLFORMcode result; |
| 701 | va_start(arg, last_post); |
| 702 | result = FormAdd(httppost, last_post, arg); |
| 703 | va_end(arg); |
| 704 | return result; |
| 705 | } |
| 706 | |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 707 | /* |
| 708 | * curl_formget() |
| 709 | * Serialize a curl_httppost struct. |
| 710 | * Returns 0 on success. |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 711 | * |
| 712 | * @unittest: 1308 |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 713 | */ |
| 714 | int curl_formget(struct curl_httppost *form, void *arg, |
| 715 | curl_formget_callback append) |
| 716 | { |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 717 | CURLcode result; |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 718 | curl_mimepart toppart; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 719 | |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 720 | Curl_mime_initpart(&toppart, NULL); /* default form is empty */ |
| 721 | result = Curl_getformdata(NULL, &toppart, form, NULL); |
| 722 | if(!result) |
| 723 | result = Curl_mime_prepare_headers(&toppart, "multipart/form-data", |
| 724 | NULL, MIMESTRATEGY_FORM); |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 725 | |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 726 | while(!result) { |
| 727 | char buffer[8192]; |
| 728 | size_t nread = Curl_mime_read(buffer, 1, sizeof buffer, &toppart); |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 729 | |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 730 | if(!nread) |
| 731 | break; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 732 | |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 733 | switch(nread) { |
| 734 | default: |
| 735 | if(append(arg, buffer, nread) != nread) |
| 736 | result = CURLE_READ_ERROR; |
| 737 | break; |
| 738 | case CURL_READFUNC_ABORT: |
| 739 | case CURL_READFUNC_PAUSE: |
| 740 | break; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 741 | } |
| 742 | } |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 743 | |
| 744 | Curl_mime_cleanpart(&toppart); |
| 745 | return (int) result; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 746 | } |
| 747 | |
| 748 | /* |
| 749 | * curl_formfree() is an external function to free up a whole form post |
| 750 | * chain |
| 751 | */ |
| 752 | void curl_formfree(struct curl_httppost *form) |
| 753 | { |
| 754 | struct curl_httppost *next; |
| 755 | |
| 756 | if(!form) |
| 757 | /* no form to free, just get out of this */ |
| 758 | return; |
| 759 | |
| 760 | do { |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 761 | next = form->next; /* the following form line */ |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 762 | |
| 763 | /* recurse to sub-contents */ |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 764 | curl_formfree(form->more); |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 765 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 766 | if(!(form->flags & HTTPPOST_PTRNAME)) |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 767 | free(form->name); /* free the name */ |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 768 | if(!(form->flags & |
| 769 | (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK)) |
| 770 | ) |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 771 | free(form->contents); /* free the contents */ |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 772 | free(form->contenttype); /* free the content type */ |
| 773 | free(form->showfilename); /* free the faked file name */ |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 774 | free(form); /* free the struct */ |
Elliott Hughes | 82be86d | 2017-09-20 17:00:17 -0700 | [diff] [blame] | 775 | form = next; |
| 776 | } while(form); /* continue */ |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 777 | } |
| 778 | |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 779 | |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 780 | /* Set mime part name, taking care of non nul-terminated name string. */ |
| 781 | static CURLcode setname(curl_mimepart *part, const char *name, size_t len) |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 782 | { |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 783 | char *zname; |
| 784 | CURLcode res; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 785 | |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 786 | if(!name || !len) |
| 787 | return curl_mime_name(part, name); |
| 788 | zname = malloc(len + 1); |
| 789 | if(!zname) |
| 790 | return CURLE_OUT_OF_MEMORY; |
| 791 | memcpy(zname, name, len); |
| 792 | zname[len] = '\0'; |
| 793 | res = curl_mime_name(part, zname); |
| 794 | free(zname); |
| 795 | return res; |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 796 | } |
| 797 | |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 798 | /* |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 799 | * Curl_getformdata() converts a linked list of "meta data" into a mime |
| 800 | * structure. The input list is in 'post', while the output is stored in |
| 801 | * mime part at '*finalform'. |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 802 | * |
| 803 | * This function will not do a failf() for the potential memory failures but |
| 804 | * should for all other errors it spots. Just note that this function MAY get |
| 805 | * a NULL pointer in the 'data' argument. |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 806 | */ |
| 807 | |
Alex Deymo | e3149cc | 2016-10-05 11:18:42 -0700 | [diff] [blame] | 808 | CURLcode Curl_getformdata(struct Curl_easy *data, |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 809 | curl_mimepart *finalform, |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 810 | struct curl_httppost *post, |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 811 | curl_read_callback fread_func) |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 812 | { |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 813 | CURLcode result = CURLE_OK; |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 814 | curl_mime *form = NULL; |
| 815 | curl_mime *multipart; |
| 816 | curl_mimepart *part; |
| 817 | struct curl_httppost *file; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 818 | |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 819 | Curl_mime_cleanpart(finalform); /* default form is empty */ |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 820 | |
| 821 | if(!post) |
| 822 | return result; /* no input => no output! */ |
| 823 | |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 824 | form = curl_mime_init(data); |
| 825 | if(!form) |
| 826 | result = CURLE_OUT_OF_MEMORY; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 827 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 828 | if(!result) |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 829 | result = curl_mime_subparts(finalform, form); |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 830 | |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 831 | /* Process each top part. */ |
| 832 | for(; !result && post; post = post->next) { |
| 833 | /* If we have more than a file here, create a mime subpart and fill it. */ |
| 834 | multipart = form; |
| 835 | if(post->more) { |
| 836 | part = curl_mime_addpart(form); |
| 837 | if(!part) |
| 838 | result = CURLE_OUT_OF_MEMORY; |
| 839 | if(!result) |
| 840 | result = setname(part, post->name, post->namelength); |
| 841 | if(!result) { |
| 842 | multipart = curl_mime_init(data); |
| 843 | if(!multipart) |
| 844 | result = CURLE_OUT_OF_MEMORY; |
| 845 | } |
| 846 | if(!result) |
| 847 | result = curl_mime_subparts(part, multipart); |
| 848 | } |
| 849 | |
| 850 | /* Generate all the part contents. */ |
| 851 | for(file = post; !result && file; file = file->more) { |
| 852 | /* Create the part. */ |
| 853 | part = curl_mime_addpart(multipart); |
| 854 | if(!part) |
| 855 | result = CURLE_OUT_OF_MEMORY; |
| 856 | |
| 857 | /* Set the headers. */ |
| 858 | if(!result) |
| 859 | result = curl_mime_headers(part, file->contentheader, 0); |
| 860 | |
| 861 | /* Set the content type. */ |
| 862 | if(!result && file->contenttype) |
| 863 | result = curl_mime_type(part, file->contenttype); |
| 864 | |
| 865 | /* Set field name. */ |
| 866 | if(!result && !post->more) |
| 867 | result = setname(part, post->name, post->namelength); |
| 868 | |
| 869 | /* Process contents. */ |
| 870 | if(!result) { |
| 871 | curl_off_t clen = post->contentslength; |
| 872 | |
| 873 | if(post->flags & CURL_HTTPPOST_LARGE) |
| 874 | clen = post->contentlen; |
| 875 | if(!clen) |
| 876 | clen = -1; |
| 877 | |
| 878 | if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) { |
| 879 | if(!strcmp(file->contents, "-")) { |
| 880 | /* There are a few cases where the code below won't work; in |
| 881 | particular, freopen(stdin) by the caller is not guaranteed |
| 882 | to result as expected. This feature has been kept for backward |
| 883 | compatibility: use of "-" pseudo file name should be avoided. */ |
| 884 | result = curl_mime_data_cb(part, (curl_off_t) -1, |
| 885 | (curl_read_callback) fread, |
| 886 | (curl_seek_callback) fseek, |
| 887 | NULL, (void *) stdin); |
| 888 | } |
| 889 | else |
| 890 | result = curl_mime_filedata(part, file->contents); |
| 891 | if(!result && (post->flags & HTTPPOST_READFILE)) |
| 892 | result = curl_mime_filename(part, NULL); |
| 893 | } |
| 894 | else if(post->flags & HTTPPOST_BUFFER) |
| 895 | result = curl_mime_data(part, post->buffer, |
| 896 | post->bufferlength? post->bufferlength: -1); |
| 897 | else if(post->flags & HTTPPOST_CALLBACK) |
| 898 | /* the contents should be read with the callback and the size is set |
| 899 | with the contentslength */ |
| 900 | result = curl_mime_data_cb(part, clen, |
| 901 | fread_func, NULL, NULL, post->userp); |
| 902 | else { |
| 903 | result = curl_mime_data(part, post->contents, (ssize_t) clen); |
| 904 | #ifdef CURL_DOES_CONVERSIONS |
| 905 | /* Convert textual contents now. */ |
| 906 | if(!result && data && part->datasize) |
| 907 | result = Curl_convert_to_network(data, part->data, part->datasize); |
| 908 | #endif |
| 909 | } |
| 910 | } |
| 911 | |
| 912 | /* Set fake file name. */ |
| 913 | if(!result && post->showfilename) |
| 914 | if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER | |
| 915 | HTTPPOST_CALLBACK))) |
| 916 | result = curl_mime_filename(part, post->showfilename); |
| 917 | } |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 918 | } |
| 919 | |
Alex Deymo | 486467e | 2017-12-19 19:04:07 +0100 | [diff] [blame] | 920 | if(result) |
| 921 | Curl_mime_cleanpart(finalform); |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 922 | |
| 923 | return result; |
| 924 | } |
| 925 | |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 926 | #else /* CURL_DISABLE_HTTP */ |
| 927 | CURLFORMcode curl_formadd(struct curl_httppost **httppost, |
| 928 | struct curl_httppost **last_post, |
| 929 | ...) |
| 930 | { |
| 931 | (void)httppost; |
| 932 | (void)last_post; |
| 933 | return CURL_FORMADD_DISABLED; |
| 934 | } |
| 935 | |
| 936 | int curl_formget(struct curl_httppost *form, void *arg, |
| 937 | curl_formget_callback append) |
| 938 | { |
| 939 | (void) form; |
| 940 | (void) arg; |
| 941 | (void) append; |
| 942 | return CURL_FORMADD_DISABLED; |
| 943 | } |
| 944 | |
| 945 | void curl_formfree(struct curl_httppost *form) |
| 946 | { |
| 947 | (void)form; |
| 948 | /* does nothing HTTP is disabled */ |
| 949 | } |
| 950 | |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 951 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 952 | #endif /* !defined(CURL_DISABLE_HTTP) */ |