1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2020, 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.haxx.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 "non-ascii.h"
37 #include "vtls/vtls.h"
43 /* The last 3 #include files should be in this order */
44 #include "curl_printf.h"
45 #include "curl_memory.h"
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
57 /***************************************************************************
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.
64 * Returns newly allocated HttpPost on success and NULL if malloc failed.
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,
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)
79 struct curl_httppost *post;
80 post = calloc(1, sizeof(struct curl_httppost));
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;
92 post->flags = flags | CURL_HTTPPOST_LARGE;
98 /* now, point our 'more' to the original 'more' */
99 post->more = parent_post->more;
101 /* then move the original 'more' to point to ourselves */
102 parent_post->more = post;
105 /* make the previous point to this */
107 (*last_post)->next = post;
116 /***************************************************************************
120 * Adds a FormInfo structure to the list presented by parent_form_info.
122 * Returns newly allocated FormInfo on success and NULL if malloc failed/
123 * parent_form_info is NULL.
125 ***************************************************************************/
126 static struct FormInfo *AddFormInfo(char *value,
128 struct FormInfo *parent_form_info)
130 struct FormInfo *form_info;
131 form_info = calloc(1, sizeof(struct FormInfo));
134 form_info->value = value;
136 form_info->contenttype = contenttype;
137 form_info->flags = HTTPPOST_FILENAME;
142 if(parent_form_info) {
143 /* now, point our 'more' to the original 'more' */
144 form_info->more = parent_form_info->more;
146 /* then move the original 'more' to point to ourselves */
147 parent_form_info->more = form_info;
153 /***************************************************************************
157 * Stores a formpost parameter and builds the appropriate linked list.
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
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).
170 * Simple name/value pair with copied contents:
171 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
172 * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
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)
179 * storing a filename (CONTENTTYPE is optional!):
180 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
181 * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
184 * storing multiple filenames:
185 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
186 * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
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
200 ***************************************************************************/
203 CURLFORMcode FormAdd(struct curl_httppost **httppost,
204 struct curl_httppost **last_post,
207 struct 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 */
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;
221 * We need to allocate the first struct to fill in.
223 first_form = calloc(1, sizeof(struct FormInfo));
225 return CURL_FORMADD_MEMORY;
227 current_form = first_form;
230 * Loop through all the options set. Break if we have an error to report.
232 while(return_value == CURL_FORMADD_OK) {
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;
240 forms++; /* advance this to next entry */
241 if(CURLFORM_END == option) {
242 /* end of array state */
248 /* This is not array-state, get next option */
249 option = va_arg(params, CURLformoption);
250 if(CURLFORM_END == option)
257 /* we don't support an array from within an array */
258 return_value = CURL_FORMADD_ILLEGAL_ARRAY;
260 forms = va_arg(params, struct curl_forms *);
264 return_value = CURL_FORMADD_NULL;
269 * Set the Name property.
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
278 current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
281 case CURLFORM_COPYNAME:
282 if(current_form->name)
283 return_value = CURL_FORMADD_OPTION_TWICE;
285 char *name = array_state?
286 array_value:va_arg(params, char *);
288 current_form->name = name; /* store for the moment */
290 return_value = CURL_FORMADD_NULL;
293 case CURLFORM_NAMELENGTH:
294 if(current_form->namelength)
295 return_value = CURL_FORMADD_OPTION_TWICE;
297 current_form->namelength =
298 array_state?(size_t)array_value:(size_t)va_arg(params, long);
302 * Set the contents property.
304 case CURLFORM_PTRCONTENTS:
305 current_form->flags |= HTTPPOST_PTRCONTENTS;
307 case CURLFORM_COPYCONTENTS:
308 if(current_form->value)
309 return_value = CURL_FORMADD_OPTION_TWICE;
312 array_state?array_value:va_arg(params, char *);
314 current_form->value = value; /* store for the moment */
316 return_value = CURL_FORMADD_NULL;
319 case CURLFORM_CONTENTSLENGTH:
320 current_form->contentslength =
321 array_state?(size_t)array_value:(size_t)va_arg(params, long);
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);
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;
335 const char *filename = array_state?
336 array_value:va_arg(params, char *);
338 current_form->value = strdup(filename);
339 if(!current_form->value)
340 return_value = CURL_FORMADD_MEMORY;
342 current_form->flags |= HTTPPOST_READFILE;
343 current_form->value_alloc = TRUE;
347 return_value = CURL_FORMADD_NULL;
351 /* We upload a file */
354 const char *filename = array_state?array_value:
355 va_arg(params, char *);
357 if(current_form->value) {
358 if(current_form->flags & HTTPPOST_FILENAME) {
360 char *fname = strdup(filename);
362 return_value = CURL_FORMADD_MEMORY;
364 form = AddFormInfo(fname, NULL, current_form);
367 return_value = CURL_FORMADD_MEMORY;
370 form->value_alloc = TRUE;
377 return_value = CURL_FORMADD_NULL;
380 return_value = CURL_FORMADD_OPTION_TWICE;
384 current_form->value = strdup(filename);
385 if(!current_form->value)
386 return_value = CURL_FORMADD_MEMORY;
388 current_form->flags |= HTTPPOST_FILENAME;
389 current_form->value_alloc = TRUE;
393 return_value = CURL_FORMADD_NULL;
398 case CURLFORM_BUFFERPTR:
399 current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
400 if(current_form->buffer)
401 return_value = CURL_FORMADD_OPTION_TWICE;
404 array_state?array_value:va_arg(params, char *);
406 current_form->buffer = buffer; /* store for the moment */
407 current_form->value = buffer; /* make it non-NULL to be accepted
411 return_value = CURL_FORMADD_NULL;
415 case CURLFORM_BUFFERLENGTH:
416 if(current_form->bufferlength)
417 return_value = CURL_FORMADD_OPTION_TWICE;
419 current_form->bufferlength =
420 array_state?(size_t)array_value:(size_t)va_arg(params, long);
423 case CURLFORM_STREAM:
424 current_form->flags |= HTTPPOST_CALLBACK;
425 if(current_form->userp)
426 return_value = CURL_FORMADD_OPTION_TWICE;
429 array_state?array_value:va_arg(params, char *);
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 */
438 return_value = CURL_FORMADD_NULL;
442 case CURLFORM_CONTENTTYPE:
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) {
449 char *type = strdup(contenttype);
451 return_value = CURL_FORMADD_MEMORY;
453 form = AddFormInfo(NULL, type, current_form);
456 return_value = CURL_FORMADD_MEMORY;
459 form->contenttype_alloc = TRUE;
466 return_value = CURL_FORMADD_NULL;
469 return_value = CURL_FORMADD_OPTION_TWICE;
473 current_form->contenttype = strdup(contenttype);
474 if(!current_form->contenttype)
475 return_value = CURL_FORMADD_MEMORY;
477 current_form->contenttype_alloc = TRUE;
480 return_value = CURL_FORMADD_NULL;
484 case CURLFORM_CONTENTHEADER:
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 *);
492 if(current_form->contentheader)
493 return_value = CURL_FORMADD_OPTION_TWICE;
495 current_form->contentheader = list;
499 case CURLFORM_FILENAME:
500 case CURLFORM_BUFFER:
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;
507 current_form->showfilename = strdup(filename);
508 if(!current_form->showfilename)
509 return_value = CURL_FORMADD_MEMORY;
511 current_form->showfilename_alloc = TRUE;
516 return_value = CURL_FORMADD_UNKNOWN_OPTION;
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;
530 if(ptr->value_alloc) {
531 Curl_safefree(ptr->value);
532 ptr->value_alloc = FALSE;
534 if(ptr->contenttype_alloc) {
535 Curl_safefree(ptr->contenttype);
536 ptr->contenttype_alloc = FALSE;
538 if(ptr->showfilename_alloc) {
539 Curl_safefree(ptr->showfilename);
540 ptr->showfilename_alloc = FALSE;
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 */
550 for(form = first_form;
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) ) ||
560 (form->flags & HTTPPOST_BUFFER) &&
561 (form->flags & HTTPPOST_PTRBUFFER) ) ||
563 ( (form->flags & HTTPPOST_READFILE) &&
564 (form->flags & HTTPPOST_PTRCONTENTS) )
566 return_value = CURL_FORMADD_INCOMPLETE;
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;
575 type = Curl_mime_contenttype(f);
579 type = FILE_CONTENTTYPE_DEFAULT;
581 /* our contenttype is missing */
582 form->contenttype = strdup(type);
583 if(!form->contenttype) {
584 return_value = CURL_FORMADD_MEMORY;
587 form->contenttype_alloc = TRUE;
589 if(form->name && form->namelength) {
590 /* Name should not contain nul bytes. */
592 for(i = 0; i < form->namelength; i++)
594 return_value = CURL_FORMADD_NULL;
597 if(return_value != CURL_FORMADD_OK)
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. */
605 /* copy name (without strdup; possibly not null-terminated) */
606 form->name = Curl_memdup(form->name, form->namelength?
608 strlen(form->name) + 1);
611 return_value = CURL_FORMADD_MEMORY;
614 form->name_alloc = TRUE;
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;
622 clen = strlen(form->value) + 1;
624 form->value = Curl_memdup(form->value, clen);
627 return_value = CURL_FORMADD_MEMORY;
630 form->value_alloc = TRUE;
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,
642 return_value = CURL_FORMADD_MEMORY;
646 if(form->contenttype)
647 prevtype = form->contenttype;
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;
659 if(ptr->value_alloc) {
660 Curl_safefree(ptr->value);
661 ptr->value_alloc = FALSE;
663 if(ptr->contenttype_alloc) {
664 Curl_safefree(ptr->contenttype);
665 ptr->contenttype_alloc = FALSE;
667 if(ptr->showfilename_alloc) {
668 Curl_safefree(ptr->showfilename);
669 ptr->showfilename_alloc = FALSE;
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 */
679 struct FormInfo *ptr = first_form->more;
688 * curl_formadd() is a public API to add a section to the multipart formpost.
693 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
694 struct curl_httppost **last_post,
699 va_start(arg, last_post);
700 result = FormAdd(httppost, last_post, arg);
707 * Serialize a curl_httppost struct.
708 * Returns 0 on success.
712 int curl_formget(struct curl_httppost *form, void *arg,
713 curl_formget_callback append)
716 curl_mimepart toppart;
718 Curl_mime_initpart(&toppart, NULL); /* default form is empty */
719 result = Curl_getformdata(NULL, &toppart, form, NULL);
721 result = Curl_mime_prepare_headers(&toppart, "multipart/form-data",
722 NULL, MIMESTRATEGY_FORM);
726 size_t nread = Curl_mime_read(buffer, 1, sizeof(buffer), &toppart);
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;
738 Curl_mime_cleanpart(&toppart);
743 * curl_formfree() is an external function to free up a whole form post
746 void curl_formfree(struct curl_httppost *form)
748 struct curl_httppost *next;
751 /* no form to free, just get out of this */
755 next = form->next; /* the following form line */
757 /* recurse to sub-contents */
758 curl_formfree(form->more);
760 if(!(form->flags & HTTPPOST_PTRNAME))
761 free(form->name); /* free the name */
763 (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
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 */
770 } while(form); /* continue */
774 /* Set mime part name, taking care of non null-terminated name string. */
775 static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
781 return curl_mime_name(part, name);
782 zname = malloc(len + 1);
784 return CURLE_OUT_OF_MEMORY;
785 memcpy(zname, name, len);
787 res = curl_mime_name(part, zname);
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'.
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.
802 CURLcode Curl_getformdata(struct Curl_easy *data,
803 curl_mimepart *finalform,
804 struct curl_httppost *post,
805 curl_read_callback fread_func)
807 CURLcode result = CURLE_OK;
808 curl_mime *form = NULL;
810 struct curl_httppost *file;
812 Curl_mime_cleanpart(finalform); /* default form is empty */
815 return result; /* no input => no output! */
817 form = curl_mime_init(data);
819 result = CURLE_OUT_OF_MEMORY;
822 result = curl_mime_subparts(finalform, form);
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;
829 part = curl_mime_addpart(form);
831 result = CURLE_OUT_OF_MEMORY;
833 result = setname(part, post->name, post->namelength);
835 multipart = curl_mime_init(data);
837 result = CURLE_OUT_OF_MEMORY;
840 result = curl_mime_subparts(part, multipart);
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);
848 result = CURLE_OUT_OF_MEMORY;
850 /* Set the headers. */
852 result = curl_mime_headers(part, file->contentheader, 0);
854 /* Set the content type. */
855 if(!result && file->contenttype)
856 result = curl_mime_type(part, file->contenttype);
858 /* Set field name. */
859 if(!result && !post->more)
860 result = setname(part, post->name, post->namelength);
862 /* Process contents. */
864 curl_off_t clen = post->contentslength;
866 if(post->flags & CURL_HTTPPOST_LARGE)
867 clen = post->contentlen;
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,
881 NULL, (void *) stdin);
884 result = curl_mime_filedata(part, file->contents);
885 if(!result && (post->flags & HTTPPOST_READFILE))
886 result = curl_mime_filename(part, NULL);
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);
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);
906 /* Set fake file name. */
907 if(!result && post->showfilename)
908 if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
910 result = curl_mime_filename(part, post->showfilename);
915 Curl_mime_cleanpart(finalform);
922 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
923 struct curl_httppost **last_post,
928 return CURL_FORMADD_DISABLED;
931 int curl_formget(struct curl_httppost *form, void *arg,
932 curl_formget_callback append)
937 return CURL_FORMADD_DISABLED;
940 void curl_formfree(struct curl_httppost *form)
943 /* does nothing HTTP is disabled */
946 #endif /* if disabled */