Annotation of embedaddon/curl/lib/formdata.c, revision 1.1.1.1
1.1 misho 1: /***************************************************************************
2: * _ _ ____ _
3: * Project ___| | | | _ \| |
4: * / __| | | | |_) | |
5: * | (__| |_| | _ <| |___
6: * \___|\___/|_| \_\_____|
7: *
8: * Copyright (C) 1998 - 2020, 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: ***************************************************************************/
67: static struct curl_httppost *
68: AddHttpPost(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: ***************************************************************************/
126: static 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:
202: static
203: CURLFORMcode 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:
693: CURLFORMcode 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: */
712: int 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: */
746: void 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 nul-terminated name string. */
775: static 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:
802: CURLcode 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: if(!clen)
869: clen = -1;
870:
871: if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
872: if(!strcmp(file->contents, "-")) {
873: /* There are a few cases where the code below won't work; in
874: particular, freopen(stdin) by the caller is not guaranteed
875: to result as expected. This feature has been kept for backward
876: compatibility: use of "-" pseudo file name should be avoided. */
877: result = curl_mime_data_cb(part, (curl_off_t) -1,
878: (curl_read_callback) fread,
879: CURLX_FUNCTION_CAST(curl_seek_callback,
880: fseek),
881: NULL, (void *) stdin);
882: }
883: else
884: result = curl_mime_filedata(part, file->contents);
885: if(!result && (post->flags & HTTPPOST_READFILE))
886: result = curl_mime_filename(part, NULL);
887: }
888: else if(post->flags & HTTPPOST_BUFFER)
889: result = curl_mime_data(part, post->buffer,
890: post->bufferlength? post->bufferlength: -1);
891: else if(post->flags & HTTPPOST_CALLBACK)
892: /* the contents should be read with the callback and the size is set
893: with the contentslength */
894: result = curl_mime_data_cb(part, clen,
895: fread_func, NULL, NULL, post->userp);
896: else {
897: result = curl_mime_data(part, post->contents, (ssize_t) clen);
898: #ifdef CURL_DOES_CONVERSIONS
899: /* Convert textual contents now. */
900: if(!result && data && part->datasize)
901: result = Curl_convert_to_network(data, part->data, part->datasize);
902: #endif
903: }
904: }
905:
906: /* Set fake file name. */
907: if(!result && post->showfilename)
908: if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
909: HTTPPOST_CALLBACK)))
910: result = curl_mime_filename(part, post->showfilename);
911: }
912: }
913:
914: if(result)
915: Curl_mime_cleanpart(finalform);
916:
917: return result;
918: }
919:
920: #else
921: /* if disabled */
922: CURLFORMcode curl_formadd(struct curl_httppost **httppost,
923: struct curl_httppost **last_post,
924: ...)
925: {
926: (void)httppost;
927: (void)last_post;
928: return CURL_FORMADD_DISABLED;
929: }
930:
931: int curl_formget(struct curl_httppost *form, void *arg,
932: curl_formget_callback append)
933: {
934: (void) form;
935: (void) arg;
936: (void) append;
937: return CURL_FORMADD_DISABLED;
938: }
939:
940: void curl_formfree(struct curl_httppost *form)
941: {
942: (void)form;
943: /* does nothing HTTP is disabled */
944: }
945:
946: #endif /* if disabled */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>