1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, 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_MIME)
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 a 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 ***************************************************************************/
68static struct curl_httppost *
69AddHttpPost(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 ***************************************************************************/
132static 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 if(value)
140 form_info->value = value;
141 if(contenttype)
142 form_info->contenttype = contenttype;
143 form_info->flags = HTTPPOST_FILENAME;
144 }
145 else
146 return NULL;
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 a 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
208static
209CURLFORMcode 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're parsing an
222 array that we got passed to us. If FALSE we're 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 */
255 option = va_arg(params, CURLformoption);
256 if(CURLFORM_END == option)
257 break;
258 }
259
260 switch(option) {
261 case CURLFORM_ARRAY:
262 if(array_state)
263 /* we don't 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:va_arg(params, curl_off_t);
328 break;
329
330 /* Get contents from a given file name */
331 case CURLFORM_FILECONTENT:
332 if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
333 return_value = CURL_FORMADD_OPTION_TWICE;
334 else {
335 const char *filename = array_state?
336 array_value:va_arg(params, char *);
337 if(filename) {
338 current_form->value = strdup(filename);
339 if(!current_form->value)
340 return_value = CURL_FORMADD_MEMORY;
341 else {
342 current_form->flags |= HTTPPOST_READFILE;
343 current_form->value_alloc = TRUE;
344 }
345 }
346 else
347 return_value = CURL_FORMADD_NULL;
348 }
349 break;
350
351 /* We upload a file */
352 case CURLFORM_FILE:
353 {
354 const char *filename = array_state?array_value:
355 va_arg(params, char *);
356
357 if(current_form->value) {
358 if(current_form->flags & HTTPPOST_FILENAME) {
359 if(filename) {
360 char *fname = strdup(filename);
361 if(!fname)
362 return_value = CURL_FORMADD_MEMORY;
363 else {
364 form = AddFormInfo(fname, NULL, current_form);
365 if(!form) {
366 free(fname);
367 return_value = CURL_FORMADD_MEMORY;
368 }
369 else {
370 form->value_alloc = TRUE;
371 current_form = form;
372 form = NULL;
373 }
374 }
375 }
376 else
377 return_value = CURL_FORMADD_NULL;
378 }
379 else
380 return_value = CURL_FORMADD_OPTION_TWICE;
381 }
382 else {
383 if(filename) {
384 current_form->value = strdup(filename);
385 if(!current_form->value)
386 return_value = CURL_FORMADD_MEMORY;
387 else {
388 current_form->flags |= HTTPPOST_FILENAME;
389 current_form->value_alloc = TRUE;
390 }
391 }
392 else
393 return_value = CURL_FORMADD_NULL;
394 }
395 break;
396 }
397
398 case CURLFORM_BUFFERPTR:
399 current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
400 if(current_form->buffer)
401 return_value = CURL_FORMADD_OPTION_TWICE;
402 else {
403 char *buffer =
404 array_state?array_value:va_arg(params, char *);
405 if(buffer) {
406 current_form->buffer = buffer; /* store for the moment */
407 current_form->value = buffer; /* make it non-NULL to be accepted
408 as fine */
409 }
410 else
411 return_value = CURL_FORMADD_NULL;
412 }
413 break;
414
415 case CURLFORM_BUFFERLENGTH:
416 if(current_form->bufferlength)
417 return_value = CURL_FORMADD_OPTION_TWICE;
418 else
419 current_form->bufferlength =
420 array_state?(size_t)array_value:(size_t)va_arg(params, long);
421 break;
422
423 case CURLFORM_STREAM:
424 current_form->flags |= HTTPPOST_CALLBACK;
425 if(current_form->userp)
426 return_value = CURL_FORMADD_OPTION_TWICE;
427 else {
428 char *userp =
429 array_state?array_value:va_arg(params, char *);
430 if(userp) {
431 current_form->userp = userp;
432 current_form->value = userp; /* this isn't strictly true but we
433 derive a value from this later on
434 and we need this non-NULL to be
435 accepted as a fine form part */
436 }
437 else
438 return_value = CURL_FORMADD_NULL;
439 }
440 break;
441
442 case CURLFORM_CONTENTTYPE:
443 {
444 const char *contenttype =
445 array_state?array_value:va_arg(params, char *);
446 if(current_form->contenttype) {
447 if(current_form->flags & HTTPPOST_FILENAME) {
448 if(contenttype) {
449 char *type = strdup(contenttype);
450 if(!type)
451 return_value = CURL_FORMADD_MEMORY;
452 else {
453 form = AddFormInfo(NULL, type, current_form);
454 if(!form) {
455 free(type);
456 return_value = CURL_FORMADD_MEMORY;
457 }
458 else {
459 form->contenttype_alloc = TRUE;
460 current_form = form;
461 form = NULL;
462 }
463 }
464 }
465 else
466 return_value = CURL_FORMADD_NULL;
467 }
468 else
469 return_value = CURL_FORMADD_OPTION_TWICE;
470 }
471 else {
472 if(contenttype) {
473 current_form->contenttype = strdup(contenttype);
474 if(!current_form->contenttype)
475 return_value = CURL_FORMADD_MEMORY;
476 else
477 current_form->contenttype_alloc = TRUE;
478 }
479 else
480 return_value = CURL_FORMADD_NULL;
481 }
482 break;
483 }
484 case CURLFORM_CONTENTHEADER:
485 {
486 /* this "cast increases required alignment of target type" but
487 we consider it OK anyway */
488 struct curl_slist *list = array_state?
489 (struct curl_slist *)(void *)array_value:
490 va_arg(params, struct curl_slist *);
491
492 if(current_form->contentheader)
493 return_value = CURL_FORMADD_OPTION_TWICE;
494 else
495 current_form->contentheader = list;
496
497 break;
498 }
499 case CURLFORM_FILENAME:
500 case CURLFORM_BUFFER:
501 {
502 const char *filename = array_state?array_value:
503 va_arg(params, char *);
504 if(current_form->showfilename)
505 return_value = CURL_FORMADD_OPTION_TWICE;
506 else {
507 current_form->showfilename = strdup(filename);
508 if(!current_form->showfilename)
509 return_value = CURL_FORMADD_MEMORY;
510 else
511 current_form->showfilename_alloc = TRUE;
512 }
513 break;
514 }
515 default:
516 return_value = CURL_FORMADD_UNKNOWN_OPTION;
517 break;
518 }
519 }
520
521 if(CURL_FORMADD_OK != return_value) {
522 /* On error, free allocated fields for all nodes of the FormInfo linked
523 list without deallocating nodes. List nodes are deallocated later on */
524 struct FormInfo *ptr;
525 for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
526 if(ptr->name_alloc) {
527 Curl_safefree(ptr->name);
528 ptr->name_alloc = FALSE;
529 }
530 if(ptr->value_alloc) {
531 Curl_safefree(ptr->value);
532 ptr->value_alloc = FALSE;
533 }
534 if(ptr->contenttype_alloc) {
535 Curl_safefree(ptr->contenttype);
536 ptr->contenttype_alloc = FALSE;
537 }
538 if(ptr->showfilename_alloc) {
539 Curl_safefree(ptr->showfilename);
540 ptr->showfilename_alloc = FALSE;
541 }
542 }
543 }
544
545 if(CURL_FORMADD_OK == return_value) {
546 /* go through the list, check for completeness and if everything is
547 * alright add the HttpPost item otherwise set return_value accordingly */
548
549 post = NULL;
550 for(form = first_form;
551 form != NULL;
552 form = form->more) {
553 if(((!form->name || !form->value) && !post) ||
554 ( (form->contentslength) &&
555 (form->flags & HTTPPOST_FILENAME) ) ||
556 ( (form->flags & HTTPPOST_FILENAME) &&
557 (form->flags & HTTPPOST_PTRCONTENTS) ) ||
558
559 ( (!form->buffer) &&
560 (form->flags & HTTPPOST_BUFFER) &&
561 (form->flags & HTTPPOST_PTRBUFFER) ) ||
562
563 ( (form->flags & HTTPPOST_READFILE) &&
564 (form->flags & HTTPPOST_PTRCONTENTS) )
565 ) {
566 return_value = CURL_FORMADD_INCOMPLETE;
567 break;
568 }
569 if(((form->flags & HTTPPOST_FILENAME) ||
570 (form->flags & HTTPPOST_BUFFER)) &&
571 !form->contenttype) {
572 char *f = (form->flags & HTTPPOST_BUFFER)?
573 form->showfilename : form->value;
574 char const *type;
575 type = Curl_mime_contenttype(f);
576 if(!type)
577 type = prevtype;
578 if(!type)
579 type = FILE_CONTENTTYPE_DEFAULT;
580
581 /* our contenttype is missing */
582 form->contenttype = strdup(type);
583 if(!form->contenttype) {
584 return_value = CURL_FORMADD_MEMORY;
585 break;
586 }
587 form->contenttype_alloc = TRUE;
588 }
589 if(form->name && form->namelength) {
590 /* Name should not contain nul bytes. */
591 size_t i;
592 for(i = 0; i < form->namelength; i++)
593 if(!form->name[i]) {
594 return_value = CURL_FORMADD_NULL;
595 break;
596 }
597 if(return_value != CURL_FORMADD_OK)
598 break;
599 }
600 if(!(form->flags & HTTPPOST_PTRNAME) &&
601 (form == first_form) ) {
602 /* Note that there's small risk that form->name is NULL here if the
603 app passed in a bad combo, so we better check for that first. */
604 if(form->name) {
605 /* copy name (without strdup; possibly not null-terminated) */
606 form->name = Curl_memdup(form->name, form->namelength?
607 form->namelength:
608 strlen(form->name) + 1);
609 }
610 if(!form->name) {
611 return_value = CURL_FORMADD_MEMORY;
612 break;
613 }
614 form->name_alloc = TRUE;
615 }
616 if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
617 HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
618 HTTPPOST_CALLBACK)) && form->value) {
619 /* copy value (without strdup; possibly contains null characters) */
620 size_t clen = (size_t) form->contentslength;
621 if(!clen)
622 clen = strlen(form->value) + 1;
623
624 form->value = Curl_memdup(form->value, clen);
625
626 if(!form->value) {
627 return_value = CURL_FORMADD_MEMORY;
628 break;
629 }
630 form->value_alloc = TRUE;
631 }
632 post = AddHttpPost(form->name, form->namelength,
633 form->value, form->contentslength,
634 form->buffer, form->bufferlength,
635 form->contenttype, form->flags,
636 form->contentheader, form->showfilename,
637 form->userp,
638 post, httppost,
639 last_post);
640
641 if(!post) {
642 return_value = CURL_FORMADD_MEMORY;
643 break;
644 }
645
646 if(form->contenttype)
647 prevtype = form->contenttype;
648 }
649 if(CURL_FORMADD_OK != return_value) {
650 /* On error, free allocated fields for nodes of the FormInfo linked
651 list which are not already owned by the httppost linked list
652 without deallocating nodes. List nodes are deallocated later on */
653 struct FormInfo *ptr;
654 for(ptr = form; ptr != NULL; ptr = ptr->more) {
655 if(ptr->name_alloc) {
656 Curl_safefree(ptr->name);
657 ptr->name_alloc = FALSE;
658 }
659 if(ptr->value_alloc) {
660 Curl_safefree(ptr->value);
661 ptr->value_alloc = FALSE;
662 }
663 if(ptr->contenttype_alloc) {
664 Curl_safefree(ptr->contenttype);
665 ptr->contenttype_alloc = FALSE;
666 }
667 if(ptr->showfilename_alloc) {
668 Curl_safefree(ptr->showfilename);
669 ptr->showfilename_alloc = FALSE;
670 }
671 }
672 }
673 }
674
675 /* Always deallocate FormInfo linked list nodes without touching node
676 fields given that these have either been deallocated or are owned
677 now by the httppost linked list */
678 while(first_form) {
679 struct FormInfo *ptr = first_form->more;
680 free(first_form);
681 first_form = ptr;
682 }
683
684 return return_value;
685}
686
687/*
688 * curl_formadd() is a public API to add a section to the multipart formpost.
689 *
690 * @unittest: 1308
691 */
692
693CURLFORMcode curl_formadd(struct curl_httppost **httppost,
694 struct curl_httppost **last_post,
695 ...)
696{
697 va_list arg;
698 CURLFORMcode result;
699 va_start(arg, last_post);
700 result = FormAdd(httppost, last_post, arg);
701 va_end(arg);
702 return result;
703}
704
705/*
706 * curl_formget()
707 * Serialize a curl_httppost struct.
708 * Returns 0 on success.
709 *
710 * @unittest: 1308
711 */
712int curl_formget(struct curl_httppost *form, void *arg,
713 curl_formget_callback append)
714{
715 CURLcode result;
716 curl_mimepart toppart;
717
718 Curl_mime_initpart(&toppart, NULL); /* default form is empty */
719 result = Curl_getformdata(NULL, &toppart, form, NULL);
720 if(!result)
721 result = Curl_mime_prepare_headers(&toppart, "multipart/form-data",
722 NULL, MIMESTRATEGY_FORM);
723
724 while(!result) {
725 char buffer[8192];
726 size_t nread = Curl_mime_read(buffer, 1, sizeof(buffer), &toppart);
727
728 if(!nread)
729 break;
730
731 if(nread > sizeof(buffer) || append(arg, buffer, nread) != nread) {
732 result = CURLE_READ_ERROR;
733 if(nread == CURL_READFUNC_ABORT)
734 result = CURLE_ABORTED_BY_CALLBACK;
735 }
736 }
737
738 Curl_mime_cleanpart(&toppart);
739 return (int) result;
740}
741
742/*
743 * curl_formfree() is an external function to free up a whole form post
744 * chain
745 */
746void curl_formfree(struct curl_httppost *form)
747{
748 struct curl_httppost *next;
749
750 if(!form)
751 /* no form to free, just get out of this */
752 return;
753
754 do {
755 next = form->next; /* the following form line */
756
757 /* recurse to sub-contents */
758 curl_formfree(form->more);
759
760 if(!(form->flags & HTTPPOST_PTRNAME))
761 free(form->name); /* free the name */
762 if(!(form->flags &
763 (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
764 )
765 free(form->contents); /* free the contents */
766 free(form->contenttype); /* free the content type */
767 free(form->showfilename); /* free the faked file name */
768 free(form); /* free the struct */
769 form = next;
770 } while(form); /* continue */
771}
772
773
774/* Set mime part name, taking care of non null-terminated name string. */
775static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
776{
777 char *zname;
778 CURLcode res;
779
780 if(!name || !len)
781 return curl_mime_name(part, name);
782 zname = malloc(len + 1);
783 if(!zname)
784 return CURLE_OUT_OF_MEMORY;
785 memcpy(zname, name, len);
786 zname[len] = '\0';
787 res = curl_mime_name(part, zname);
788 free(zname);
789 return res;
790}
791
792/*
793 * Curl_getformdata() converts a linked list of "meta data" into a mime
794 * structure. The input list is in 'post', while the output is stored in
795 * mime part at '*finalform'.
796 *
797 * This function will not do a failf() for the potential memory failures but
798 * should for all other errors it spots. Just note that this function MAY get
799 * a NULL pointer in the 'data' argument.
800 */
801
802CURLcode Curl_getformdata(struct Curl_easy *data,
803 curl_mimepart *finalform,
804 struct curl_httppost *post,
805 curl_read_callback fread_func)
806{
807 CURLcode result = CURLE_OK;
808 curl_mime *form = NULL;
809 curl_mimepart *part;
810 struct curl_httppost *file;
811
812 Curl_mime_cleanpart(finalform); /* default form is empty */
813
814 if(!post)
815 return result; /* no input => no output! */
816
817 form = curl_mime_init(data);
818 if(!form)
819 result = CURLE_OUT_OF_MEMORY;
820
821 if(!result)
822 result = curl_mime_subparts(finalform, form);
823
824 /* Process each top part. */
825 for(; !result && post; post = post->next) {
826 /* If we have more than a file here, create a mime subpart and fill it. */
827 curl_mime *multipart = form;
828 if(post->more) {
829 part = curl_mime_addpart(form);
830 if(!part)
831 result = CURLE_OUT_OF_MEMORY;
832 if(!result)
833 result = setname(part, post->name, post->namelength);
834 if(!result) {
835 multipart = curl_mime_init(data);
836 if(!multipart)
837 result = CURLE_OUT_OF_MEMORY;
838 }
839 if(!result)
840 result = curl_mime_subparts(part, multipart);
841 }
842
843 /* Generate all the part contents. */
844 for(file = post; !result && file; file = file->more) {
845 /* Create the part. */
846 part = curl_mime_addpart(multipart);
847 if(!part)
848 result = CURLE_OUT_OF_MEMORY;
849
850 /* Set the headers. */
851 if(!result)
852 result = curl_mime_headers(part, file->contentheader, 0);
853
854 /* Set the content type. */
855 if(!result && file->contenttype)
856 result = curl_mime_type(part, file->contenttype);
857
858 /* Set field name. */
859 if(!result && !post->more)
860 result = setname(part, post->name, post->namelength);
861
862 /* Process contents. */
863 if(!result) {
864 curl_off_t clen = post->contentslength;
865
866 if(post->flags & CURL_HTTPPOST_LARGE)
867 clen = post->contentlen;
868
869 if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
870 if(!strcmp(file->contents, "-")) {
871 /* There are a few cases where the code below won't work; in
872 particular, freopen(stdin) by the caller is not guaranteed
873 to result as expected. This feature has been kept for backward
874 compatibility: use of "-" pseudo file name should be avoided. */
875 result = curl_mime_data_cb(part, (curl_off_t) -1,
876 (curl_read_callback) fread,
877 CURLX_FUNCTION_CAST(curl_seek_callback,
878 fseek),
879 NULL, (void *) stdin);
880 }
881 else
882 result = curl_mime_filedata(part, file->contents);
883 if(!result && (post->flags & HTTPPOST_READFILE))
884 result = curl_mime_filename(part, NULL);
885 }
886 else if(post->flags & HTTPPOST_BUFFER)
887 result = curl_mime_data(part, post->buffer,
888 post->bufferlength? post->bufferlength: -1);
889 else if(post->flags & HTTPPOST_CALLBACK) {
890 /* the contents should be read with the callback and the size is set
891 with the contentslength */
892 if(!clen)
893 clen = -1;
894 result = curl_mime_data_cb(part, clen,
895 fread_func, NULL, NULL, post->userp);
896 }
897 else {
898 size_t uclen;
899 if(!clen)
900 uclen = CURL_ZERO_TERMINATED;
901 else
902 uclen = (size_t)clen;
903 result = curl_mime_data(part, post->contents, uclen);
904 }
905 }
906
907 /* Set fake file name. */
908 if(!result && post->showfilename)
909 if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
910 HTTPPOST_CALLBACK)))
911 result = curl_mime_filename(part, post->showfilename);
912 }
913 }
914
915 if(result)
916 Curl_mime_cleanpart(finalform);
917
918 return result;
919}
920
921#else
922/* if disabled */
923CURLFORMcode curl_formadd(struct curl_httppost **httppost,
924 struct curl_httppost **last_post,
925 ...)
926{
927 (void)httppost;
928 (void)last_post;
929 return CURL_FORMADD_DISABLED;
930}
931
932int curl_formget(struct curl_httppost *form, void *arg,
933 curl_formget_callback append)
934{
935 (void) form;
936 (void) arg;
937 (void) append;
938 return CURL_FORMADD_DISABLED;
939}
940
941void curl_formfree(struct curl_httppost *form)
942{
943 (void)form;
944 /* does nothing HTTP is disabled */
945}
946
947#endif /* if disabled */
948