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