1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
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.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 #include "curl_setup.h"
25 #include <curl/curl.h>
28 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)
30 #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
34 #include "urldata.h" /* for struct Curl_easy */
36 #include "vtls/vtls.h"
42 /* The last 3 #include files should be in this order */
43 #include "curl_printf.h"
44 #include "curl_memory.h"
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
56 /***************************************************************************
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.
63 * Returns newly allocated HttpPost on success and NULL if malloc failed.
65 ***************************************************************************/
66 static struct curl_httppost *
67 AddHttpPost(char *name, size_t namelength,
68 char *value, curl_off_t contentslength,
69 char *buffer, size_t bufferlength,
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)
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 */
84 post = calloc(1, sizeof(struct curl_httppost));
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;
96 post->flags = flags | CURL_HTTPPOST_LARGE;
102 /* now, point our 'more' to the original 'more' */
103 post->more = parent_post->more;
105 /* then move the original 'more' to point to ourselves */
106 parent_post->more = post;
109 /* make the previous point to this */
111 (*last_post)->next = post;
120 /***************************************************************************
124 * Adds a FormInfo structure to the list presented by parent_form_info.
126 * Returns newly allocated FormInfo on success and NULL if malloc failed/
127 * parent_form_info is NULL.
129 ***************************************************************************/
130 static struct FormInfo *AddFormInfo(char *value,
132 struct FormInfo *parent_form_info)
134 struct FormInfo *form_info;
135 form_info = calloc(1, sizeof(struct FormInfo));
138 form_info->value = value;
140 form_info->contenttype = contenttype;
141 form_info->flags = HTTPPOST_FILENAME;
146 if(parent_form_info) {
147 /* now, point our 'more' to the original 'more' */
148 form_info->more = parent_form_info->more;
150 /* then move the original 'more' to point to ourselves */
151 parent_form_info->more = form_info;
157 /***************************************************************************
161 * Stores a formpost parameter and builds the appropriate linked list.
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
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).
174 * Simple name/value pair with copied contents:
175 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
176 * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
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)
183 * storing a filename (CONTENTTYPE is optional!):
184 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
185 * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
188 * storing multiple filenames:
189 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
190 * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
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
204 ***************************************************************************/
207 CURLFORMcode FormAdd(struct curl_httppost **httppost,
208 struct curl_httppost **last_post,
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 */
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;
225 * We need to allocate the first struct to fill in.
227 first_form = calloc(1, sizeof(struct FormInfo));
229 return CURL_FORMADD_MEMORY;
231 current_form = first_form;
234 * Loop through all the options set. Break if we have an error to report.
236 while(return_value == CURL_FORMADD_OK) {
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;
244 forms++; /* advance this to next entry */
245 if(CURLFORM_END == option) {
246 /* end of array state */
252 /* This is not array-state, get next option */
253 option = va_arg(params, CURLformoption);
254 if(CURLFORM_END == option)
261 /* we don't support an array from within an array */
262 return_value = CURL_FORMADD_ILLEGAL_ARRAY;
264 forms = va_arg(params, struct curl_forms *);
268 return_value = CURL_FORMADD_NULL;
273 * Set the Name property.
275 case CURLFORM_PTRNAME:
276 current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
279 case CURLFORM_COPYNAME:
280 if(current_form->name)
281 return_value = CURL_FORMADD_OPTION_TWICE;
283 char *name = array_state?
284 array_value:va_arg(params, char *);
286 current_form->name = name; /* store for the moment */
288 return_value = CURL_FORMADD_NULL;
291 case CURLFORM_NAMELENGTH:
292 if(current_form->namelength)
293 return_value = CURL_FORMADD_OPTION_TWICE;
295 current_form->namelength =
296 array_state?(size_t)array_value:(size_t)va_arg(params, long);
300 * Set the contents property.
302 case CURLFORM_PTRCONTENTS:
303 current_form->flags |= HTTPPOST_PTRCONTENTS;
305 case CURLFORM_COPYCONTENTS:
306 if(current_form->value)
307 return_value = CURL_FORMADD_OPTION_TWICE;
310 array_state?array_value:va_arg(params, char *);
312 current_form->value = value; /* store for the moment */
314 return_value = CURL_FORMADD_NULL;
317 case CURLFORM_CONTENTSLENGTH:
318 current_form->contentslength =
319 array_state?(size_t)array_value:(size_t)va_arg(params, long);
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);
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;
333 const char *filename = array_state?
334 array_value:va_arg(params, char *);
336 current_form->value = strdup(filename);
337 if(!current_form->value)
338 return_value = CURL_FORMADD_MEMORY;
340 current_form->flags |= HTTPPOST_READFILE;
341 current_form->value_alloc = TRUE;
345 return_value = CURL_FORMADD_NULL;
349 /* We upload a file */
352 const char *filename = array_state?array_value:
353 va_arg(params, char *);
355 if(current_form->value) {
356 if(current_form->flags & HTTPPOST_FILENAME) {
358 char *fname = strdup(filename);
360 return_value = CURL_FORMADD_MEMORY;
362 form = AddFormInfo(fname, NULL, current_form);
365 return_value = CURL_FORMADD_MEMORY;
368 form->value_alloc = TRUE;
375 return_value = CURL_FORMADD_NULL;
378 return_value = CURL_FORMADD_OPTION_TWICE;
382 current_form->value = strdup(filename);
383 if(!current_form->value)
384 return_value = CURL_FORMADD_MEMORY;
386 current_form->flags |= HTTPPOST_FILENAME;
387 current_form->value_alloc = TRUE;
391 return_value = CURL_FORMADD_NULL;
396 case CURLFORM_BUFFERPTR:
397 current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
398 if(current_form->buffer)
399 return_value = CURL_FORMADD_OPTION_TWICE;
402 array_state?array_value:va_arg(params, char *);
404 current_form->buffer = buffer; /* store for the moment */
405 current_form->value = buffer; /* make it non-NULL to be accepted
409 return_value = CURL_FORMADD_NULL;
413 case CURLFORM_BUFFERLENGTH:
414 if(current_form->bufferlength)
415 return_value = CURL_FORMADD_OPTION_TWICE;
417 current_form->bufferlength =
418 array_state?(size_t)array_value:(size_t)va_arg(params, long);
421 case CURLFORM_STREAM:
422 current_form->flags |= HTTPPOST_CALLBACK;
423 if(current_form->userp)
424 return_value = CURL_FORMADD_OPTION_TWICE;
427 array_state?array_value:va_arg(params, char *);
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 */
436 return_value = CURL_FORMADD_NULL;
440 case CURLFORM_CONTENTTYPE:
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) {
447 char *type = strdup(contenttype);
449 return_value = CURL_FORMADD_MEMORY;
451 form = AddFormInfo(NULL, type, current_form);
454 return_value = CURL_FORMADD_MEMORY;
457 form->contenttype_alloc = TRUE;
464 return_value = CURL_FORMADD_NULL;
467 return_value = CURL_FORMADD_OPTION_TWICE;
471 current_form->contenttype = strdup(contenttype);
472 if(!current_form->contenttype)
473 return_value = CURL_FORMADD_MEMORY;
475 current_form->contenttype_alloc = TRUE;
478 return_value = CURL_FORMADD_NULL;
482 case CURLFORM_CONTENTHEADER:
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 *);
490 if(current_form->contentheader)
491 return_value = CURL_FORMADD_OPTION_TWICE;
493 current_form->contentheader = list;
497 case CURLFORM_FILENAME:
498 case CURLFORM_BUFFER:
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;
505 current_form->showfilename = strdup(filename);
506 if(!current_form->showfilename)
507 return_value = CURL_FORMADD_MEMORY;
509 current_form->showfilename_alloc = TRUE;
514 return_value = CURL_FORMADD_UNKNOWN_OPTION;
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;
528 if(ptr->value_alloc) {
529 Curl_safefree(ptr->value);
530 ptr->value_alloc = FALSE;
532 if(ptr->contenttype_alloc) {
533 Curl_safefree(ptr->contenttype);
534 ptr->contenttype_alloc = FALSE;
536 if(ptr->showfilename_alloc) {
537 Curl_safefree(ptr->showfilename);
538 ptr->showfilename_alloc = FALSE;
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 */
548 for(form = first_form;
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) ) ||
558 (form->flags & HTTPPOST_BUFFER) &&
559 (form->flags & HTTPPOST_PTRBUFFER) ) ||
561 ( (form->flags & HTTPPOST_READFILE) &&
562 (form->flags & HTTPPOST_PTRCONTENTS) )
564 return_value = CURL_FORMADD_INCOMPLETE;
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;
573 type = Curl_mime_contenttype(f);
577 type = FILE_CONTENTTYPE_DEFAULT;
579 /* our contenttype is missing */
580 form->contenttype = strdup(type);
581 if(!form->contenttype) {
582 return_value = CURL_FORMADD_MEMORY;
585 form->contenttype_alloc = TRUE;
587 if(form->name && form->namelength) {
588 /* Name should not contain nul bytes. */
590 for(i = 0; i < form->namelength; i++)
592 return_value = CURL_FORMADD_NULL;
595 if(return_value != CURL_FORMADD_OK)
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. */
603 /* copy name (without strdup; possibly not null-terminated) */
604 form->name = Curl_memdup(form->name, form->namelength?
606 strlen(form->name) + 1);
609 return_value = CURL_FORMADD_MEMORY;
612 form->name_alloc = TRUE;
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;
620 clen = strlen(form->value) + 1;
622 form->value = Curl_memdup(form->value, clen);
625 return_value = CURL_FORMADD_MEMORY;
628 form->value_alloc = TRUE;
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,
640 return_value = CURL_FORMADD_MEMORY;
644 if(form->contenttype)
645 prevtype = form->contenttype;
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;
657 if(ptr->value_alloc) {
658 Curl_safefree(ptr->value);
659 ptr->value_alloc = FALSE;
661 if(ptr->contenttype_alloc) {
662 Curl_safefree(ptr->contenttype);
663 ptr->contenttype_alloc = FALSE;
665 if(ptr->showfilename_alloc) {
666 Curl_safefree(ptr->showfilename);
667 ptr->showfilename_alloc = FALSE;
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 */
677 struct FormInfo *ptr = first_form->more;
686 * curl_formadd() is a public API to add a section to the multipart formpost.
691 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
692 struct curl_httppost **last_post,
697 va_start(arg, last_post);
698 result = FormAdd(httppost, last_post, arg);
705 * Serialize a curl_httppost struct.
706 * Returns 0 on success.
710 int curl_formget(struct curl_httppost *form, void *arg,
711 curl_formget_callback append)
714 curl_mimepart toppart;
716 Curl_mime_initpart(&toppart, NULL); /* default form is empty */
717 result = Curl_getformdata(NULL, &toppart, form, NULL);
719 result = Curl_mime_prepare_headers(&toppart, "multipart/form-data",
720 NULL, MIMESTRATEGY_FORM);
724 size_t nread = Curl_mime_read(buffer, 1, sizeof(buffer), &toppart);
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;
736 Curl_mime_cleanpart(&toppart);
741 * curl_formfree() is an external function to free up a whole form post
744 void curl_formfree(struct curl_httppost *form)
746 struct curl_httppost *next;
749 /* no form to free, just get out of this */
753 next = form->next; /* the following form line */
755 /* recurse to sub-contents */
756 curl_formfree(form->more);
758 if(!(form->flags & HTTPPOST_PTRNAME))
759 free(form->name); /* free the name */
761 (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
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 */
768 } while(form); /* continue */
772 /* Set mime part name, taking care of non null-terminated name string. */
773 static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
779 return curl_mime_name(part, name);
780 zname = malloc(len + 1);
782 return CURLE_OUT_OF_MEMORY;
783 memcpy(zname, name, len);
785 res = curl_mime_name(part, zname);
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'.
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.
800 CURLcode Curl_getformdata(struct Curl_easy *data,
801 curl_mimepart *finalform,
802 struct curl_httppost *post,
803 curl_read_callback fread_func)
805 CURLcode result = CURLE_OK;
806 curl_mime *form = NULL;
808 struct curl_httppost *file;
810 Curl_mime_cleanpart(finalform); /* default form is empty */
813 return result; /* no input => no output! */
815 form = curl_mime_init(data);
817 result = CURLE_OUT_OF_MEMORY;
820 result = curl_mime_subparts(finalform, form);
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;
827 part = curl_mime_addpart(form);
829 result = CURLE_OUT_OF_MEMORY;
831 result = setname(part, post->name, post->namelength);
833 multipart = curl_mime_init(data);
835 result = CURLE_OUT_OF_MEMORY;
838 result = curl_mime_subparts(part, multipart);
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);
846 result = CURLE_OUT_OF_MEMORY;
848 /* Set the headers. */
850 result = curl_mime_headers(part, file->contentheader, 0);
852 /* Set the content type. */
853 if(!result && file->contenttype)
854 result = curl_mime_type(part, file->contenttype);
856 /* Set field name. */
857 if(!result && !post->more)
858 result = setname(part, post->name, post->namelength);
860 /* Process contents. */
862 curl_off_t clen = post->contentslength;
864 if(post->flags & CURL_HTTPPOST_LARGE)
865 clen = post->contentlen;
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,
877 NULL, (void *) stdin);
880 result = curl_mime_filedata(part, file->contents);
881 if(!result && (post->flags & HTTPPOST_READFILE))
882 result = curl_mime_filename(part, NULL);
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 */
892 result = curl_mime_data_cb(part, clen,
893 fread_func, NULL, NULL, post->userp);
898 uclen = CURL_ZERO_TERMINATED;
900 uclen = (size_t)clen;
901 result = curl_mime_data(part, post->contents, uclen);
905 /* Set fake file name. */
906 if(!result && post->showfilename)
907 if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
909 result = curl_mime_filename(part, post->showfilename);
914 Curl_mime_cleanpart(finalform);
921 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
922 struct curl_httppost **last_post,
927 return CURL_FORMADD_DISABLED;
930 int curl_formget(struct curl_httppost *form, void *arg,
931 curl_formget_callback append)
936 return CURL_FORMADD_DISABLED;
939 void curl_formfree(struct curl_httppost *form)
942 /* does nothing HTTP is disabled */
945 #endif /* if disabled */