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 ***************************************************************************/
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(s: 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 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
206static
207CURLFORMcode 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're parsing an
220 array that we got passed to us. If FALSE we're 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 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(value: fname, NULL, parent_form_info: 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, contenttype: type, parent_form_info: 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(filename: 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(src: form->name, buffer_length: form->namelength?
607 form->namelength:
608 strlen(s: 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(s: form->value) + 1;
623
624 form->value = Curl_memdup(src: form->value, buffer_length: clen);
625
626 if(!form->value) {
627 return_value = CURL_FORMADD_MEMORY;
628 break;
629 }
630 form->value_alloc = TRUE;
631 }
632 post = AddHttpPost(name: form->name, namelength: form->namelength,
633 value: form->value, contentslength: form->contentslength,
634 buffer: form->buffer, bufferlength: form->bufferlength,
635 contenttype: form->contenttype, flags: form->flags,
636 contentHeader: form->contentheader, showfilename: form->showfilename,
637 userp: form->userp,
638 parent_post: 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, params: 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(part: &toppart); /* default form is empty */
719 result = Curl_getformdata(NULL, &toppart, post: form, NULL);
720 if(!result)
721 result = Curl_mime_prepare_headers(NULL, part: &toppart, contenttype: "multipart/form-data",
722 NULL, strategy: MIMESTRATEGY_FORM);
723
724 while(!result) {
725 char buffer[8192];
726 size_t nread = Curl_mime_read(buffer, size: 1, nitems: sizeof(buffer), instream: &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(part: &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: 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(dest: zname, src: name, n: len);
786 zname[len] = '\0';
787 res = curl_mime_name(part, name: zname);
788 free(zname);
789 return res;
790}
791
792/* wrap call to fseeko so it matches the calling convention of callback */
793static int fseeko_wrapper(void *stream, curl_off_t offset, int whence)
794{
795#if defined(HAVE_FSEEKO)
796 return fseeko(stream: stream, off: (off_t)offset, whence: whence);
797#elif defined(HAVE__FSEEKI64)
798 return _fseeki64(stream, (__int64)offset, whence);
799#else
800 if(offset > LONG_MAX)
801 return -1;
802 return fseek(stream, (long)offset, whence);
803#endif
804}
805
806/*
807 * Curl_getformdata() converts a linked list of "meta data" into a mime
808 * structure. The input list is in 'post', while the output is stored in
809 * mime part at '*finalform'.
810 *
811 * This function will not do a failf() for the potential memory failures but
812 * should for all other errors it spots. Just note that this function MAY get
813 * a NULL pointer in the 'data' argument.
814 */
815
816CURLcode Curl_getformdata(struct Curl_easy *data,
817 curl_mimepart *finalform,
818 struct curl_httppost *post,
819 curl_read_callback fread_func)
820{
821 CURLcode result = CURLE_OK;
822 curl_mime *form = NULL;
823 curl_mimepart *part;
824 struct curl_httppost *file;
825
826 Curl_mime_cleanpart(part: finalform); /* default form is empty */
827
828 if(!post)
829 return result; /* no input => no output! */
830
831 form = curl_mime_init(easy: data);
832 if(!form)
833 result = CURLE_OUT_OF_MEMORY;
834
835 if(!result)
836 result = curl_mime_subparts(part: finalform, subparts: form);
837
838 /* Process each top part. */
839 for(; !result && post; post = post->next) {
840 /* If we have more than a file here, create a mime subpart and fill it. */
841 curl_mime *multipart = form;
842 if(post->more) {
843 part = curl_mime_addpart(mime: form);
844 if(!part)
845 result = CURLE_OUT_OF_MEMORY;
846 if(!result)
847 result = setname(part, name: post->name, len: post->namelength);
848 if(!result) {
849 multipart = curl_mime_init(easy: data);
850 if(!multipart)
851 result = CURLE_OUT_OF_MEMORY;
852 }
853 if(!result)
854 result = curl_mime_subparts(part, subparts: multipart);
855 }
856
857 /* Generate all the part contents. */
858 for(file = post; !result && file; file = file->more) {
859 /* Create the part. */
860 part = curl_mime_addpart(mime: multipart);
861 if(!part)
862 result = CURLE_OUT_OF_MEMORY;
863
864 /* Set the headers. */
865 if(!result)
866 result = curl_mime_headers(part, headers: file->contentheader, take_ownership: 0);
867
868 /* Set the content type. */
869 if(!result && file->contenttype)
870 result = curl_mime_type(part, mimetype: file->contenttype);
871
872 /* Set field name. */
873 if(!result && !post->more)
874 result = setname(part, name: post->name, len: post->namelength);
875
876 /* Process contents. */
877 if(!result) {
878 curl_off_t clen = post->contentslength;
879
880 if(post->flags & CURL_HTTPPOST_LARGE)
881 clen = post->contentlen;
882
883 if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
884 if(!strcmp(s1: file->contents, s2: "-")) {
885 /* There are a few cases where the code below won't work; in
886 particular, freopen(stdin) by the caller is not guaranteed
887 to result as expected. This feature has been kept for backward
888 compatibility: use of "-" pseudo file name should be avoided. */
889 result = curl_mime_data_cb(part, datasize: (curl_off_t) -1,
890 readfunc: (curl_read_callback) fread,
891 seekfunc: fseeko_wrapper,
892 NULL, arg: (void *) stdin);
893 }
894 else
895 result = curl_mime_filedata(part, filename: file->contents);
896 if(!result && (post->flags & HTTPPOST_READFILE))
897 result = curl_mime_filename(part, NULL);
898 }
899 else if(post->flags & HTTPPOST_BUFFER)
900 result = curl_mime_data(part, data: post->buffer,
901 datasize: post->bufferlength? 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, datasize: clen,
908 readfunc: fread_func, NULL, NULL, arg: 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, data: post->contents, datasize: uclen);
917 }
918 }
919
920 /* Set fake file name. */
921 if(!result && post->showfilename)
922 if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
923 HTTPPOST_CALLBACK)))
924 result = curl_mime_filename(part, filename: post->showfilename);
925 }
926 }
927
928 if(result)
929 Curl_mime_cleanpart(part: finalform);
930
931 return result;
932}
933
934#else
935/* if disabled */
936CURLFORMcode 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
945int 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
954void curl_formfree(struct curl_httppost *form)
955{
956 (void)form;
957 /* Nothing to do. */
958}
959
960#endif /* if disabled */
961