VirtualBox

source: vbox/trunk/src/libs/curl-7.83.1/lib/formdata.c@ 97138

最後變更 在這個檔案從97138是 95312,由 vboxsync 提交於 3 年 前

libs/{curl,libxml2}: OSE export fixes, bugref:8515

  • 屬性 svn:eol-style 設為 native
檔案大小: 29.1 KB
 
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 ***************************************************************************/
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 "vtls/vtls.h"
37#include "strcase.h"
38#include "sendf.h"
39#include "strdup.h"
40#include "rand.h"
41#include "warnless.h"
42/* The last 3 #include files should be in this order */
43#include "curl_printf.h"
44#include "curl_memory.h"
45#include "memdebug.h"
46
47
48#define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
49#define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
50#define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
51#define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
52#define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
53#define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
54#define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER
55
56/***************************************************************************
57 *
58 * AddHttpPost()
59 *
60 * Adds a HttpPost structure to the list, if parent_post is given becomes
61 * a subpost of parent_post instead of a direct list element.
62 *
63 * Returns newly allocated HttpPost on success and NULL if malloc failed.
64 *
65 ***************************************************************************/
66static struct curl_httppost *
67AddHttpPost(char *name, size_t namelength,
68 char *value, curl_off_t contentslength,
69 char *buffer, size_t bufferlength,
70 char *contenttype,
71 long flags,
72 struct curl_slist *contentHeader,
73 char *showfilename, char *userp,
74 struct curl_httppost *parent_post,
75 struct curl_httppost **httppost,
76 struct curl_httppost **last_post)
77{
78 struct curl_httppost *post;
79 if(!namelength && name)
80 namelength = strlen(name);
81 if((bufferlength > LONG_MAX) || (namelength > LONG_MAX))
82 /* avoid overflow in typecasts below */
83 return NULL;
84 post = calloc(1, sizeof(struct curl_httppost));
85 if(post) {
86 post->name = name;
87 post->namelength = (long)namelength;
88 post->contents = value;
89 post->contentlen = contentslength;
90 post->buffer = buffer;
91 post->bufferlength = (long)bufferlength;
92 post->contenttype = contenttype;
93 post->contentheader = contentHeader;
94 post->showfilename = showfilename;
95 post->userp = userp;
96 post->flags = flags | CURL_HTTPPOST_LARGE;
97 }
98 else
99 return NULL;
100
101 if(parent_post) {
102 /* now, point our 'more' to the original 'more' */
103 post->more = parent_post->more;
104
105 /* then move the original 'more' to point to ourselves */
106 parent_post->more = post;
107 }
108 else {
109 /* make the previous point to this */
110 if(*last_post)
111 (*last_post)->next = post;
112 else
113 (*httppost) = post;
114
115 (*last_post) = post;
116 }
117 return post;
118}
119
120/***************************************************************************
121 *
122 * AddFormInfo()
123 *
124 * Adds a FormInfo structure to the list presented by parent_form_info.
125 *
126 * Returns newly allocated FormInfo on success and NULL if malloc failed/
127 * parent_form_info is NULL.
128 *
129 ***************************************************************************/
130static struct FormInfo *AddFormInfo(char *value,
131 char *contenttype,
132 struct FormInfo *parent_form_info)
133{
134 struct FormInfo *form_info;
135 form_info = calloc(1, sizeof(struct FormInfo));
136 if(form_info) {
137 if(value)
138 form_info->value = value;
139 if(contenttype)
140 form_info->contenttype = contenttype;
141 form_info->flags = HTTPPOST_FILENAME;
142 }
143 else
144 return NULL;
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 a 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 */
253 option = va_arg(params, CURLformoption);
254 if(CURLFORM_END == option)
255 break;
256 }
257
258 switch(option) {
259 case CURLFORM_ARRAY:
260 if(array_state)
261 /* we don't support an array from within an array */
262 return_value = CURL_FORMADD_ILLEGAL_ARRAY;
263 else {
264 forms = va_arg(params, struct curl_forms *);
265 if(forms)
266 array_state = TRUE;
267 else
268 return_value = CURL_FORMADD_NULL;
269 }
270 break;
271
272 /*
273 * Set the Name property.
274 */
275 case CURLFORM_PTRNAME:
276 current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
277
278 /* FALLTHROUGH */
279 case CURLFORM_COPYNAME:
280 if(current_form->name)
281 return_value = CURL_FORMADD_OPTION_TWICE;
282 else {
283 char *name = array_state?
284 array_value:va_arg(params, char *);
285 if(name)
286 current_form->name = name; /* store for the moment */
287 else
288 return_value = CURL_FORMADD_NULL;
289 }
290 break;
291 case CURLFORM_NAMELENGTH:
292 if(current_form->namelength)
293 return_value = CURL_FORMADD_OPTION_TWICE;
294 else
295 current_form->namelength =
296 array_state?(size_t)array_value:(size_t)va_arg(params, long);
297 break;
298
299 /*
300 * Set the contents property.
301 */
302 case CURLFORM_PTRCONTENTS:
303 current_form->flags |= HTTPPOST_PTRCONTENTS;
304 /* FALLTHROUGH */
305 case CURLFORM_COPYCONTENTS:
306 if(current_form->value)
307 return_value = CURL_FORMADD_OPTION_TWICE;
308 else {
309 char *value =
310 array_state?array_value:va_arg(params, char *);
311 if(value)
312 current_form->value = value; /* store for the moment */
313 else
314 return_value = CURL_FORMADD_NULL;
315 }
316 break;
317 case CURLFORM_CONTENTSLENGTH:
318 current_form->contentslength =
319 array_state?(size_t)array_value:(size_t)va_arg(params, long);
320 break;
321
322 case CURLFORM_CONTENTLEN:
323 current_form->flags |= CURL_HTTPPOST_LARGE;
324 current_form->contentslength =
325 array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
326 break;
327
328 /* Get contents from a given file name */
329 case CURLFORM_FILECONTENT:
330 if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
331 return_value = CURL_FORMADD_OPTION_TWICE;
332 else {
333 const char *filename = array_state?
334 array_value:va_arg(params, char *);
335 if(filename) {
336 current_form->value = strdup(filename);
337 if(!current_form->value)
338 return_value = CURL_FORMADD_MEMORY;
339 else {
340 current_form->flags |= HTTPPOST_READFILE;
341 current_form->value_alloc = TRUE;
342 }
343 }
344 else
345 return_value = CURL_FORMADD_NULL;
346 }
347 break;
348
349 /* We upload a file */
350 case CURLFORM_FILE:
351 {
352 const char *filename = array_state?array_value:
353 va_arg(params, char *);
354
355 if(current_form->value) {
356 if(current_form->flags & HTTPPOST_FILENAME) {
357 if(filename) {
358 char *fname = strdup(filename);
359 if(!fname)
360 return_value = CURL_FORMADD_MEMORY;
361 else {
362 form = AddFormInfo(fname, NULL, current_form);
363 if(!form) {
364 free(fname);
365 return_value = CURL_FORMADD_MEMORY;
366 }
367 else {
368 form->value_alloc = TRUE;
369 current_form = form;
370 form = NULL;
371 }
372 }
373 }
374 else
375 return_value = CURL_FORMADD_NULL;
376 }
377 else
378 return_value = CURL_FORMADD_OPTION_TWICE;
379 }
380 else {
381 if(filename) {
382 current_form->value = strdup(filename);
383 if(!current_form->value)
384 return_value = CURL_FORMADD_MEMORY;
385 else {
386 current_form->flags |= HTTPPOST_FILENAME;
387 current_form->value_alloc = TRUE;
388 }
389 }
390 else
391 return_value = CURL_FORMADD_NULL;
392 }
393 break;
394 }
395
396 case CURLFORM_BUFFERPTR:
397 current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
398 if(current_form->buffer)
399 return_value = CURL_FORMADD_OPTION_TWICE;
400 else {
401 char *buffer =
402 array_state?array_value:va_arg(params, char *);
403 if(buffer) {
404 current_form->buffer = buffer; /* store for the moment */
405 current_form->value = buffer; /* make it non-NULL to be accepted
406 as fine */
407 }
408 else
409 return_value = CURL_FORMADD_NULL;
410 }
411 break;
412
413 case CURLFORM_BUFFERLENGTH:
414 if(current_form->bufferlength)
415 return_value = CURL_FORMADD_OPTION_TWICE;
416 else
417 current_form->bufferlength =
418 array_state?(size_t)array_value:(size_t)va_arg(params, long);
419 break;
420
421 case CURLFORM_STREAM:
422 current_form->flags |= HTTPPOST_CALLBACK;
423 if(current_form->userp)
424 return_value = CURL_FORMADD_OPTION_TWICE;
425 else {
426 char *userp =
427 array_state?array_value:va_arg(params, char *);
428 if(userp) {
429 current_form->userp = userp;
430 current_form->value = userp; /* this isn't strictly true but we
431 derive a value from this later on
432 and we need this non-NULL to be
433 accepted as a fine form part */
434 }
435 else
436 return_value = CURL_FORMADD_NULL;
437 }
438 break;
439
440 case CURLFORM_CONTENTTYPE:
441 {
442 const char *contenttype =
443 array_state?array_value:va_arg(params, char *);
444 if(current_form->contenttype) {
445 if(current_form->flags & HTTPPOST_FILENAME) {
446 if(contenttype) {
447 char *type = strdup(contenttype);
448 if(!type)
449 return_value = CURL_FORMADD_MEMORY;
450 else {
451 form = AddFormInfo(NULL, type, current_form);
452 if(!form) {
453 free(type);
454 return_value = CURL_FORMADD_MEMORY;
455 }
456 else {
457 form->contenttype_alloc = TRUE;
458 current_form = form;
459 form = NULL;
460 }
461 }
462 }
463 else
464 return_value = CURL_FORMADD_NULL;
465 }
466 else
467 return_value = CURL_FORMADD_OPTION_TWICE;
468 }
469 else {
470 if(contenttype) {
471 current_form->contenttype = strdup(contenttype);
472 if(!current_form->contenttype)
473 return_value = CURL_FORMADD_MEMORY;
474 else
475 current_form->contenttype_alloc = TRUE;
476 }
477 else
478 return_value = CURL_FORMADD_NULL;
479 }
480 break;
481 }
482 case CURLFORM_CONTENTHEADER:
483 {
484 /* this "cast increases required alignment of target type" but
485 we consider it OK anyway */
486 struct curl_slist *list = array_state?
487 (struct curl_slist *)(void *)array_value:
488 va_arg(params, struct curl_slist *);
489
490 if(current_form->contentheader)
491 return_value = CURL_FORMADD_OPTION_TWICE;
492 else
493 current_form->contentheader = list;
494
495 break;
496 }
497 case CURLFORM_FILENAME:
498 case CURLFORM_BUFFER:
499 {
500 const char *filename = array_state?array_value:
501 va_arg(params, char *);
502 if(current_form->showfilename)
503 return_value = CURL_FORMADD_OPTION_TWICE;
504 else {
505 current_form->showfilename = strdup(filename);
506 if(!current_form->showfilename)
507 return_value = CURL_FORMADD_MEMORY;
508 else
509 current_form->showfilename_alloc = TRUE;
510 }
511 break;
512 }
513 default:
514 return_value = CURL_FORMADD_UNKNOWN_OPTION;
515 break;
516 }
517 }
518
519 if(CURL_FORMADD_OK != return_value) {
520 /* On error, free allocated fields for all nodes of the FormInfo linked
521 list without deallocating nodes. List nodes are deallocated later on */
522 struct FormInfo *ptr;
523 for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
524 if(ptr->name_alloc) {
525 Curl_safefree(ptr->name);
526 ptr->name_alloc = FALSE;
527 }
528 if(ptr->value_alloc) {
529 Curl_safefree(ptr->value);
530 ptr->value_alloc = FALSE;
531 }
532 if(ptr->contenttype_alloc) {
533 Curl_safefree(ptr->contenttype);
534 ptr->contenttype_alloc = FALSE;
535 }
536 if(ptr->showfilename_alloc) {
537 Curl_safefree(ptr->showfilename);
538 ptr->showfilename_alloc = FALSE;
539 }
540 }
541 }
542
543 if(CURL_FORMADD_OK == return_value) {
544 /* go through the list, check for completeness and if everything is
545 * alright add the HttpPost item otherwise set return_value accordingly */
546
547 post = NULL;
548 for(form = first_form;
549 form != NULL;
550 form = form->more) {
551 if(((!form->name || !form->value) && !post) ||
552 ( (form->contentslength) &&
553 (form->flags & HTTPPOST_FILENAME) ) ||
554 ( (form->flags & HTTPPOST_FILENAME) &&
555 (form->flags & HTTPPOST_PTRCONTENTS) ) ||
556
557 ( (!form->buffer) &&
558 (form->flags & HTTPPOST_BUFFER) &&
559 (form->flags & HTTPPOST_PTRBUFFER) ) ||
560
561 ( (form->flags & HTTPPOST_READFILE) &&
562 (form->flags & HTTPPOST_PTRCONTENTS) )
563 ) {
564 return_value = CURL_FORMADD_INCOMPLETE;
565 break;
566 }
567 if(((form->flags & HTTPPOST_FILENAME) ||
568 (form->flags & HTTPPOST_BUFFER)) &&
569 !form->contenttype) {
570 char *f = (form->flags & HTTPPOST_BUFFER)?
571 form->showfilename : form->value;
572 char const *type;
573 type = Curl_mime_contenttype(f);
574 if(!type)
575 type = prevtype;
576 if(!type)
577 type = FILE_CONTENTTYPE_DEFAULT;
578
579 /* our contenttype is missing */
580 form->contenttype = strdup(type);
581 if(!form->contenttype) {
582 return_value = CURL_FORMADD_MEMORY;
583 break;
584 }
585 form->contenttype_alloc = TRUE;
586 }
587 if(form->name && form->namelength) {
588 /* Name should not contain nul bytes. */
589 size_t i;
590 for(i = 0; i < form->namelength; i++)
591 if(!form->name[i]) {
592 return_value = CURL_FORMADD_NULL;
593 break;
594 }
595 if(return_value != CURL_FORMADD_OK)
596 break;
597 }
598 if(!(form->flags & HTTPPOST_PTRNAME) &&
599 (form == first_form) ) {
600 /* Note that there's small risk that form->name is NULL here if the
601 app passed in a bad combo, so we better check for that first. */
602 if(form->name) {
603 /* copy name (without strdup; possibly not null-terminated) */
604 form->name = Curl_memdup(form->name, form->namelength?
605 form->namelength:
606 strlen(form->name) + 1);
607 }
608 if(!form->name) {
609 return_value = CURL_FORMADD_MEMORY;
610 break;
611 }
612 form->name_alloc = TRUE;
613 }
614 if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
615 HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
616 HTTPPOST_CALLBACK)) && form->value) {
617 /* copy value (without strdup; possibly contains null characters) */
618 size_t clen = (size_t) form->contentslength;
619 if(!clen)
620 clen = strlen(form->value) + 1;
621
622 form->value = Curl_memdup(form->value, clen);
623
624 if(!form->value) {
625 return_value = CURL_FORMADD_MEMORY;
626 break;
627 }
628 form->value_alloc = TRUE;
629 }
630 post = AddHttpPost(form->name, form->namelength,
631 form->value, form->contentslength,
632 form->buffer, form->bufferlength,
633 form->contenttype, form->flags,
634 form->contentheader, form->showfilename,
635 form->userp,
636 post, httppost,
637 last_post);
638
639 if(!post) {
640 return_value = CURL_FORMADD_MEMORY;
641 break;
642 }
643
644 if(form->contenttype)
645 prevtype = form->contenttype;
646 }
647 if(CURL_FORMADD_OK != return_value) {
648 /* On error, free allocated fields for nodes of the FormInfo linked
649 list which are not already owned by the httppost linked list
650 without deallocating nodes. List nodes are deallocated later on */
651 struct FormInfo *ptr;
652 for(ptr = form; ptr != NULL; ptr = ptr->more) {
653 if(ptr->name_alloc) {
654 Curl_safefree(ptr->name);
655 ptr->name_alloc = FALSE;
656 }
657 if(ptr->value_alloc) {
658 Curl_safefree(ptr->value);
659 ptr->value_alloc = FALSE;
660 }
661 if(ptr->contenttype_alloc) {
662 Curl_safefree(ptr->contenttype);
663 ptr->contenttype_alloc = FALSE;
664 }
665 if(ptr->showfilename_alloc) {
666 Curl_safefree(ptr->showfilename);
667 ptr->showfilename_alloc = FALSE;
668 }
669 }
670 }
671 }
672
673 /* Always deallocate FormInfo linked list nodes without touching node
674 fields given that these have either been deallocated or are owned
675 now by the httppost linked list */
676 while(first_form) {
677 struct FormInfo *ptr = first_form->more;
678 free(first_form);
679 first_form = ptr;
680 }
681
682 return return_value;
683}
684
685/*
686 * curl_formadd() is a public API to add a section to the multipart formpost.
687 *
688 * @unittest: 1308
689 */
690
691CURLFORMcode curl_formadd(struct curl_httppost **httppost,
692 struct curl_httppost **last_post,
693 ...)
694{
695 va_list arg;
696 CURLFORMcode result;
697 va_start(arg, last_post);
698 result = FormAdd(httppost, last_post, arg);
699 va_end(arg);
700 return result;
701}
702
703/*
704 * curl_formget()
705 * Serialize a curl_httppost struct.
706 * Returns 0 on success.
707 *
708 * @unittest: 1308
709 */
710int curl_formget(struct curl_httppost *form, void *arg,
711 curl_formget_callback append)
712{
713 CURLcode result;
714 curl_mimepart toppart;
715
716 Curl_mime_initpart(&toppart, NULL); /* default form is empty */
717 result = Curl_getformdata(NULL, &toppart, form, NULL);
718 if(!result)
719 result = Curl_mime_prepare_headers(&toppart, "multipart/form-data",
720 NULL, MIMESTRATEGY_FORM);
721
722 while(!result) {
723 char buffer[8192];
724 size_t nread = Curl_mime_read(buffer, 1, sizeof(buffer), &toppart);
725
726 if(!nread)
727 break;
728
729 if(nread > sizeof(buffer) || append(arg, buffer, nread) != nread) {
730 result = CURLE_READ_ERROR;
731 if(nread == CURL_READFUNC_ABORT)
732 result = CURLE_ABORTED_BY_CALLBACK;
733 }
734 }
735
736 Curl_mime_cleanpart(&toppart);
737 return (int) result;
738}
739
740/*
741 * curl_formfree() is an external function to free up a whole form post
742 * chain
743 */
744void curl_formfree(struct curl_httppost *form)
745{
746 struct curl_httppost *next;
747
748 if(!form)
749 /* no form to free, just get out of this */
750 return;
751
752 do {
753 next = form->next; /* the following form line */
754
755 /* recurse to sub-contents */
756 curl_formfree(form->more);
757
758 if(!(form->flags & HTTPPOST_PTRNAME))
759 free(form->name); /* free the name */
760 if(!(form->flags &
761 (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
762 )
763 free(form->contents); /* free the contents */
764 free(form->contenttype); /* free the content type */
765 free(form->showfilename); /* free the faked file name */
766 free(form); /* free the struct */
767 form = next;
768 } while(form); /* continue */
769}
770
771
772/* Set mime part name, taking care of non null-terminated name string. */
773static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
774{
775 char *zname;
776 CURLcode res;
777
778 if(!name || !len)
779 return curl_mime_name(part, name);
780 zname = malloc(len + 1);
781 if(!zname)
782 return CURLE_OUT_OF_MEMORY;
783 memcpy(zname, name, len);
784 zname[len] = '\0';
785 res = curl_mime_name(part, zname);
786 free(zname);
787 return res;
788}
789
790/*
791 * Curl_getformdata() converts a linked list of "meta data" into a mime
792 * structure. The input list is in 'post', while the output is stored in
793 * mime part at '*finalform'.
794 *
795 * This function will not do a failf() for the potential memory failures but
796 * should for all other errors it spots. Just note that this function MAY get
797 * a NULL pointer in the 'data' argument.
798 */
799
800CURLcode Curl_getformdata(struct Curl_easy *data,
801 curl_mimepart *finalform,
802 struct curl_httppost *post,
803 curl_read_callback fread_func)
804{
805 CURLcode result = CURLE_OK;
806 curl_mime *form = NULL;
807 curl_mimepart *part;
808 struct curl_httppost *file;
809
810 Curl_mime_cleanpart(finalform); /* default form is empty */
811
812 if(!post)
813 return result; /* no input => no output! */
814
815 form = curl_mime_init(data);
816 if(!form)
817 result = CURLE_OUT_OF_MEMORY;
818
819 if(!result)
820 result = curl_mime_subparts(finalform, form);
821
822 /* Process each top part. */
823 for(; !result && post; post = post->next) {
824 /* If we have more than a file here, create a mime subpart and fill it. */
825 curl_mime *multipart = form;
826 if(post->more) {
827 part = curl_mime_addpart(form);
828 if(!part)
829 result = CURLE_OUT_OF_MEMORY;
830 if(!result)
831 result = setname(part, post->name, post->namelength);
832 if(!result) {
833 multipart = curl_mime_init(data);
834 if(!multipart)
835 result = CURLE_OUT_OF_MEMORY;
836 }
837 if(!result)
838 result = curl_mime_subparts(part, multipart);
839 }
840
841 /* Generate all the part contents. */
842 for(file = post; !result && file; file = file->more) {
843 /* Create the part. */
844 part = curl_mime_addpart(multipart);
845 if(!part)
846 result = CURLE_OUT_OF_MEMORY;
847
848 /* Set the headers. */
849 if(!result)
850 result = curl_mime_headers(part, file->contentheader, 0);
851
852 /* Set the content type. */
853 if(!result && file->contenttype)
854 result = curl_mime_type(part, file->contenttype);
855
856 /* Set field name. */
857 if(!result && !post->more)
858 result = setname(part, post->name, post->namelength);
859
860 /* Process contents. */
861 if(!result) {
862 curl_off_t clen = post->contentslength;
863
864 if(post->flags & CURL_HTTPPOST_LARGE)
865 clen = post->contentlen;
866
867 if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
868 if(!strcmp(file->contents, "-")) {
869 /* There are a few cases where the code below won't work; in
870 particular, freopen(stdin) by the caller is not guaranteed
871 to result as expected. This feature has been kept for backward
872 compatibility: use of "-" pseudo file name should be avoided. */
873 result = curl_mime_data_cb(part, (curl_off_t) -1,
874 (curl_read_callback) fread,
875 CURLX_FUNCTION_CAST(curl_seek_callback,
876 fseek),
877 NULL, (void *) stdin);
878 }
879 else
880 result = curl_mime_filedata(part, file->contents);
881 if(!result && (post->flags & HTTPPOST_READFILE))
882 result = curl_mime_filename(part, NULL);
883 }
884 else if(post->flags & HTTPPOST_BUFFER)
885 result = curl_mime_data(part, post->buffer,
886 post->bufferlength? post->bufferlength: -1);
887 else if(post->flags & HTTPPOST_CALLBACK) {
888 /* the contents should be read with the callback and the size is set
889 with the contentslength */
890 if(!clen)
891 clen = -1;
892 result = curl_mime_data_cb(part, clen,
893 fread_func, NULL, NULL, post->userp);
894 }
895 else {
896 size_t uclen;
897 if(!clen)
898 uclen = CURL_ZERO_TERMINATED;
899 else
900 uclen = (size_t)clen;
901 result = curl_mime_data(part, post->contents, uclen);
902 }
903 }
904
905 /* Set fake file name. */
906 if(!result && post->showfilename)
907 if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
908 HTTPPOST_CALLBACK)))
909 result = curl_mime_filename(part, post->showfilename);
910 }
911 }
912
913 if(result)
914 Curl_mime_cleanpart(finalform);
915
916 return result;
917}
918
919#else
920/* if disabled */
921CURLFORMcode curl_formadd(struct curl_httppost **httppost,
922 struct curl_httppost **last_post,
923 ...)
924{
925 (void)httppost;
926 (void)last_post;
927 return CURL_FORMADD_DISABLED;
928}
929
930int curl_formget(struct curl_httppost *form, void *arg,
931 curl_formget_callback append)
932{
933 (void) form;
934 (void) arg;
935 (void) append;
936 return CURL_FORMADD_DISABLED;
937}
938
939void curl_formfree(struct curl_httppost *form)
940{
941 (void)form;
942 /* does nothing HTTP is disabled */
943}
944
945#endif /* if disabled */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette