1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2019, 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.haxx.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 ***************************************************************************/
22
23#include "curl_setup.h"
24
25#include <curl/curl.h>
26
27#include "formdata.h"
28#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)
29
30#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
31#include <libgen.h>
32#endif
33
34#include "urldata.h" /* for struct Curl_easy */
35#include "mime.h"
36#include "non-ascii.h"
37#include "vtls/vtls.h"
38#include "strcase.h"
39#include "sendf.h"
40#include "strdup.h"
41#include "rand.h"
42#include "warnless.h"
43/* The last 3 #include files should be in this order */
44#include "curl_printf.h"
45#include "curl_memory.h"
46#include "memdebug.h"
47
48
49#define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
50#define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
51#define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
52#define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
53#define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
54#define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
55#define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER
56
57/***************************************************************************
58 *
59 * AddHttpPost()
60 *
61 * Adds a HttpPost structure to the list, if parent_post is given becomes
62 * a subpost of parent_post instead of a direct list element.
63 *
64 * Returns newly allocated HttpPost on success and NULL if malloc failed.
65 *
66 ***************************************************************************/
67static struct curl_httppost *
68AddHttpPost(char *name, size_t namelength,
69 char *value, curl_off_t contentslength,
70 char *buffer, size_t bufferlength,
71 char *contenttype,
72 long flags,
73 struct curl_slist *contentHeader,
74 char *showfilename, char *userp,
75 struct curl_httppost *parent_post,
76 struct curl_httppost **httppost,
77 struct curl_httppost **last_post)
78{
79 struct curl_httppost *post;
80 post = calloc(1, sizeof(struct curl_httppost));
81 if(post) {
82 post->name = name;
83 post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
84 post->contents = value;
85 post->contentlen = contentslength;
86 post->buffer = buffer;
87 post->bufferlength = (long)bufferlength;
88 post->contenttype = contenttype;
89 post->contentheader = contentHeader;
90 post->showfilename = showfilename;
91 post->userp = userp;
92 post->flags = flags | CURL_HTTPPOST_LARGE;
93 }
94 else
95 return NULL;
96
97 if(parent_post) {
98 /* now, point our 'more' to the original 'more' */
99 post->more = parent_post->more;
100
101 /* then move the original 'more' to point to ourselves */
102 parent_post->more = post;
103 }
104 else {
105 /* make the previous point to this */
106 if(*last_post)
107 (*last_post)->next = post;
108 else
109 (*httppost) = post;
110
111 (*last_post) = post;
112 }
113 return post;
114}
115
116/***************************************************************************
117 *
118 * AddFormInfo()
119 *
120 * Adds a FormInfo structure to the list presented by parent_form_info.
121 *
122 * Returns newly allocated FormInfo on success and NULL if malloc failed/
123 * parent_form_info is NULL.
124 *
125 ***************************************************************************/
126static FormInfo * AddFormInfo(char *value,
127 char *contenttype,
128 FormInfo *parent_form_info)
129{
130 FormInfo *form_info;
131 form_info = calloc(1, sizeof(struct FormInfo));
132 if(form_info) {
133 if(value)
134 form_info->value = value;
135 if(contenttype)
136 form_info->contenttype = contenttype;
137 form_info->flags = HTTPPOST_FILENAME;
138 }
139 else
140 return NULL;
141
142 if(parent_form_info) {
143 /* now, point our 'more' to the original 'more' */
144 form_info->more = parent_form_info->more;
145
146 /* then move the original 'more' to point to ourselves */
147 parent_form_info->more = form_info;
148 }
149
150 return form_info;
151}
152
153/***************************************************************************
154 *
155 * FormAdd()
156 *
157 * Stores a formpost parameter and builds the appropriate linked list.
158 *
159 * Has two principal functionalities: using files and byte arrays as
160 * post parts. Byte arrays are either copied or just the pointer is stored
161 * (as the user requests) while for files only the filename and not the
162 * content is stored.
163 *
164 * While you may have only one byte array for each name, multiple filenames
165 * are allowed (and because of this feature CURLFORM_END is needed after
166 * using CURLFORM_FILE).
167 *
168 * Examples:
169 *
170 * Simple name/value pair with copied contents:
171 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
172 * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
173 *
174 * name/value pair where only the content pointer is remembered:
175 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
176 * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
177 * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
178 *
179 * storing a filename (CONTENTTYPE is optional!):
180 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
181 * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
182 * CURLFORM_END);
183 *
184 * storing multiple filenames:
185 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
186 * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
187 *
188 * Returns:
189 * CURL_FORMADD_OK on success
190 * CURL_FORMADD_MEMORY if the FormInfo allocation fails
191 * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
192 * CURL_FORMADD_NULL if a null pointer was given for a char
193 * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
194 * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
195 * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error)
196 * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated
197 * CURL_FORMADD_MEMORY if some allocation for string copying failed.
198 * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
199 *
200 ***************************************************************************/
201
202static
203CURLFORMcode FormAdd(struct curl_httppost **httppost,
204 struct curl_httppost **last_post,
205 va_list params)
206{
207 FormInfo *first_form, *current_form, *form = NULL;
208 CURLFORMcode return_value = CURL_FORMADD_OK;
209 const char *prevtype = NULL;
210 struct curl_httppost *post = NULL;
211 CURLformoption option;
212 struct curl_forms *forms = NULL;
213 char *array_value = NULL; /* value read from an array */
214
215 /* This is a state variable, that if TRUE means that we're parsing an
216 array that we got passed to us. If FALSE we're parsing the input
217 va_list arguments. */
218 bool array_state = FALSE;
219
220 /*
221 * We need to allocate the first struct to fill in.
222 */
223 first_form = calloc(1, sizeof(struct FormInfo));
224 if(!first_form)
225 return CURL_FORMADD_MEMORY;
226
227 current_form = first_form;
228
229 /*
230 * Loop through all the options set. Break if we have an error to report.
231 */
232 while(return_value == CURL_FORMADD_OK) {
233
234 /* first see if we have more parts of the array param */
235 if(array_state && forms) {
236 /* get the upcoming option from the given array */
237 option = forms->option;
238 array_value = (char *)forms->value;
239
240 forms++; /* advance this to next entry */
241 if(CURLFORM_END == option) {
242 /* end of array state */
243 array_state = FALSE;
244 continue;
245 }
246 }
247 else {
248 /* This is not array-state, get next option */
249 option = va_arg(params, CURLformoption);
250 if(CURLFORM_END == option)
251 break;
252 }
253
254 switch(option) {
255 case CURLFORM_ARRAY:
256 if(array_state)
257 /* we don't support an array from within an array */
258 return_value = CURL_FORMADD_ILLEGAL_ARRAY;
259 else {
260 forms = va_arg(params, struct curl_forms *);
261 if(forms)
262 array_state = TRUE;
263 else
264 return_value = CURL_FORMADD_NULL;
265 }
266 break;
267
268 /*
269 * Set the Name property.
270 */
271 case CURLFORM_PTRNAME:
272#ifdef CURL_DOES_CONVERSIONS
273 /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy
274 * the data in all cases so that we'll have safe memory for the eventual
275 * conversion.
276 */
277#else
278 current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
279#endif
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 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 nul-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 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 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 switch(nread) {
732 default:
733 if(append(arg, buffer, nread) != nread)
734 result = CURLE_READ_ERROR;
735 break;
736 case CURL_READFUNC_ABORT:
737 case CURL_READFUNC_PAUSE:
738 break;
739 }
740 }
741
742 Curl_mime_cleanpart(&toppart);
743 return (int) result;
744}
745
746/*
747 * curl_formfree() is an external function to free up a whole form post
748 * chain
749 */
750void curl_formfree(struct curl_httppost *form)
751{
752 struct curl_httppost *next;
753
754 if(!form)
755 /* no form to free, just get out of this */
756 return;
757
758 do {
759 next = form->next; /* the following form line */
760
761 /* recurse to sub-contents */
762 curl_formfree(form->more);
763
764 if(!(form->flags & HTTPPOST_PTRNAME))
765 free(form->name); /* free the name */
766 if(!(form->flags &
767 (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
768 )
769 free(form->contents); /* free the contents */
770 free(form->contenttype); /* free the content type */
771 free(form->showfilename); /* free the faked file name */
772 free(form); /* free the struct */
773 form = next;
774 } while(form); /* continue */
775}
776
777
778/* Set mime part name, taking care of non nul-terminated name string. */
779static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
780{
781 char *zname;
782 CURLcode res;
783
784 if(!name || !len)
785 return curl_mime_name(part, name);
786 zname = malloc(len + 1);
787 if(!zname)
788 return CURLE_OUT_OF_MEMORY;
789 memcpy(zname, name, len);
790 zname[len] = '\0';
791 res = curl_mime_name(part, zname);
792 free(zname);
793 return res;
794}
795
796/*
797 * Curl_getformdata() converts a linked list of "meta data" into a mime
798 * structure. The input list is in 'post', while the output is stored in
799 * mime part at '*finalform'.
800 *
801 * This function will not do a failf() for the potential memory failures but
802 * should for all other errors it spots. Just note that this function MAY get
803 * a NULL pointer in the 'data' argument.
804 */
805
806CURLcode Curl_getformdata(struct Curl_easy *data,
807 curl_mimepart *finalform,
808 struct curl_httppost *post,
809 curl_read_callback fread_func)
810{
811 CURLcode result = CURLE_OK;
812 curl_mime *form = NULL;
813 curl_mimepart *part;
814 struct curl_httppost *file;
815
816 Curl_mime_cleanpart(finalform); /* default form is empty */
817
818 if(!post)
819 return result; /* no input => no output! */
820
821 form = curl_mime_init(data);
822 if(!form)
823 result = CURLE_OUT_OF_MEMORY;
824
825 if(!result)
826 result = curl_mime_subparts(finalform, form);
827
828 /* Process each top part. */
829 for(; !result && post; post = post->next) {
830 /* If we have more than a file here, create a mime subpart and fill it. */
831 curl_mime *multipart = form;
832 if(post->more) {
833 part = curl_mime_addpart(form);
834 if(!part)
835 result = CURLE_OUT_OF_MEMORY;
836 if(!result)
837 result = setname(part, post->name, post->namelength);
838 if(!result) {
839 multipart = curl_mime_init(data);
840 if(!multipart)
841 result = CURLE_OUT_OF_MEMORY;
842 }
843 if(!result)
844 result = curl_mime_subparts(part, multipart);
845 }
846
847 /* Generate all the part contents. */
848 for(file = post; !result && file; file = file->more) {
849 /* Create the part. */
850 part = curl_mime_addpart(multipart);
851 if(!part)
852 result = CURLE_OUT_OF_MEMORY;
853
854 /* Set the headers. */
855 if(!result)
856 result = curl_mime_headers(part, file->contentheader, 0);
857
858 /* Set the content type. */
859 if(!result && file->contenttype)
860 result = curl_mime_type(part, file->contenttype);
861
862 /* Set field name. */
863 if(!result && !post->more)
864 result = setname(part, post->name, post->namelength);
865
866 /* Process contents. */
867 if(!result) {
868 curl_off_t clen = post->contentslength;
869
870 if(post->flags & CURL_HTTPPOST_LARGE)
871 clen = post->contentlen;
872 if(!clen)
873 clen = -1;
874
875 if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
876 if(!strcmp(file->contents, "-")) {
877 /* There are a few cases where the code below won't work; in
878 particular, freopen(stdin) by the caller is not guaranteed
879 to result as expected. This feature has been kept for backward
880 compatibility: use of "-" pseudo file name should be avoided. */
881 result = curl_mime_data_cb(part, (curl_off_t) -1,
882 (curl_read_callback) fread,
883 CURLX_FUNCTION_CAST(curl_seek_callback,
884 fseek),
885 NULL, (void *) stdin);
886 }
887 else
888 result = curl_mime_filedata(part, file->contents);
889 if(!result && (post->flags & HTTPPOST_READFILE))
890 result = curl_mime_filename(part, NULL);
891 }
892 else if(post->flags & HTTPPOST_BUFFER)
893 result = curl_mime_data(part, post->buffer,
894 post->bufferlength? post->bufferlength: -1);
895 else if(post->flags & HTTPPOST_CALLBACK)
896 /* the contents should be read with the callback and the size is set
897 with the contentslength */
898 result = curl_mime_data_cb(part, clen,
899 fread_func, NULL, NULL, post->userp);
900 else {
901 result = curl_mime_data(part, post->contents, (ssize_t) clen);
902#ifdef CURL_DOES_CONVERSIONS
903 /* Convert textual contents now. */
904 if(!result && data && part->datasize)
905 result = Curl_convert_to_network(data, part->data, part->datasize);
906#endif
907 }
908 }
909
910 /* Set fake file name. */
911 if(!result && post->showfilename)
912 if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
913 HTTPPOST_CALLBACK)))
914 result = curl_mime_filename(part, post->showfilename);
915 }
916 }
917
918 if(result)
919 Curl_mime_cleanpart(finalform);
920
921 return result;
922}
923
924#else
925/* if disabled */
926CURLFORMcode curl_formadd(struct curl_httppost **httppost,
927 struct curl_httppost **last_post,
928 ...)
929{
930 (void)httppost;
931 (void)last_post;
932 return CURL_FORMADD_DISABLED;
933}
934
935int curl_formget(struct curl_httppost *form, void *arg,
936 curl_formget_callback append)
937{
938 (void) form;
939 (void) arg;
940 (void) append;
941 return CURL_FORMADD_DISABLED;
942}
943
944void curl_formfree(struct curl_httppost *form)
945{
946 (void)form;
947 /* does nothing HTTP is disabled */
948}
949
950#endif /* if disabled */
951