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