1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2004, 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 http://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.
22 ***************************************************************************/
25 Debug the form generator stand-alone by compiling this source file with:
27 gcc -DHAVE_CONFIG_H -I../ -g -D_FORM_DEBUG -o formdata -I../include formdata.c strequal.c
29 run the 'formdata' executable the output should end with:
30 All Tests seem to have worked ...
31 and the following parts should be there:
33 Content-Disposition: form-data; name="simple_COPYCONTENTS"
34 value for simple COPYCONTENTS
36 Content-Disposition: form-data; name="COPYCONTENTS_+_CONTENTTYPE"
37 Content-Type: image/gif
38 value for COPYCONTENTS + CONTENTTYPE
40 Content-Disposition: form-data; name="PRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH"
41 vlue for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH
42 (or you might see P^@RNAME and v^@lue at the start)
44 Content-Disposition: form-data; name="simple_PTRCONTENTS"
45 value for simple PTRCONTENTS
47 Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH"
48 vlue for PTRCONTENTS + CONTENTSLENGTH
49 (or you might see v^@lue at the start)
51 Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE"
52 Content-Type: text/plain
53 vlue for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE
54 (or you might see v^@lue at the start)
56 Content-Disposition: form-data; name="FILE1_+_CONTENTTYPE"; filename="inet_ntoa_r.h"
57 Content-Type: text/html
60 Content-Disposition: form-data; name="FILE1_+_FILE2"
61 Content-Type: multipart/mixed, boundary=curlz1s0dkticx49MV1KGcYP5cvfSsz
63 Content-Disposition: attachment; filename="inet_ntoa_r.h"
64 Content-Type: text/plain
66 Content-Disposition: attachment; filename="Makefile.b32.resp"
67 Content-Type: text/plain
70 Content-Disposition: form-data; name="FILE1_+_FILE2_+_FILE3"
71 Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1
73 Content-Disposition: attachment; filename="inet_ntoa_r.h"
74 Content-Type: text/plain
76 Content-Disposition: attachment; filename="Makefile.b32.resp"
77 Content-Type: text/plain
79 Content-Disposition: attachment; filename="inet_ntoa_r.h"
80 Content-Type: text/plain
84 Content-Disposition: form-data; name="ARRAY: FILE1_+_FILE2_+_FILE3"
85 Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1
87 Content-Disposition: attachment; filename="inet_ntoa_r.h"
88 Content-Type: text/plain
90 Content-Disposition: attachment; filename="Makefile.b32.resp"
91 Content-Type: text/plain
93 Content-Disposition: attachment; filename="inet_ntoa_r.h"
94 Content-Type: text/plain
97 Content-Disposition: form-data; name="FILECONTENT"
103 #include <curl/curl.h>
105 /* Length of the random boundary string. */
106 #define BOUNDARY_LENGTH 40
108 #ifndef CURL_DISABLE_HTTP
115 #include <sys/stat.h>
116 #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
119 #include "formdata.h"
120 #include "strequal.h"
123 #define _MPRINTF_REPLACE /* use our functions only */
124 #include <curl/mprintf.h>
126 /* The last #include file should be: */
127 #include "memdebug.h"
129 /* What kind of Content-Type to use on un-specified files with unrecognized
131 #define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
133 #define FORM_FILE_SEPARATOR ','
134 #define FORM_TYPE_SEPARATOR ';'
136 /***************************************************************************
140 * Adds a HttpPost structure to the list, if parent_post is given becomes
141 * a subpost of parent_post instead of a direct list element.
143 * Returns newly allocated HttpPost on success and NULL if malloc failed.
145 ***************************************************************************/
146 static struct curl_httppost *
147 AddHttpPost(char * name, size_t namelength,
148 char * value, size_t contentslength,
149 char * buffer, size_t bufferlength,
152 struct curl_slist* contentHeader,
154 struct curl_httppost *parent_post,
155 struct curl_httppost **httppost,
156 struct curl_httppost **last_post)
158 struct curl_httppost *post;
159 post = (struct curl_httppost *)calloc(sizeof(struct curl_httppost), 1);
162 post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
163 post->contents = value;
164 post->contentslength = (long)contentslength;
165 post->buffer = buffer;
166 post->bufferlength = (long)bufferlength;
167 post->contenttype = contenttype;
168 post->contentheader = contentHeader;
169 post->showfilename = showfilename;
176 /* now, point our 'more' to the original 'more' */
177 post->more = parent_post->more;
179 /* then move the original 'more' to point to ourselves */
180 parent_post->more = post;
183 /* make the previous point to this */
185 (*last_post)->next = post;
194 /***************************************************************************
198 * Adds a FormInfo structure to the list presented by parent_form_info.
200 * Returns newly allocated FormInfo on success and NULL if malloc failed/
201 * parent_form_info is NULL.
203 ***************************************************************************/
204 static FormInfo * AddFormInfo(char *value,
206 FormInfo *parent_form_info)
209 form_info = (FormInfo *)malloc(sizeof(FormInfo));
211 memset(form_info, 0, sizeof(FormInfo));
213 form_info->value = value;
215 form_info->contenttype = contenttype;
216 form_info->flags = HTTPPOST_FILENAME;
221 if (parent_form_info) {
222 /* now, point our 'more' to the original 'more' */
223 form_info->more = parent_form_info->more;
225 /* then move the original 'more' to point to ourselves */
226 parent_form_info->more = form_info;
234 /***************************************************************************
236 * ContentTypeForFilename()
238 * Provides content type for filename if one of the known types (else
239 * (either the prevtype or the default is returned).
241 * Returns some valid contenttype for filename.
243 ***************************************************************************/
244 static const char * ContentTypeForFilename (const char *filename,
245 const char *prevtype)
247 const char *contenttype = NULL;
250 * No type was specified, we scan through a few well-known
251 * extensions and pick the first we match!
254 const char *extension;
257 static struct ContentType ctts[]={
258 {".gif", "image/gif"},
259 {".jpg", "image/jpeg"},
260 {".jpeg", "image/jpeg"},
261 {".txt", "text/plain"},
262 {".html", "text/html"}
266 /* default to the previously set/used! */
267 contenttype = prevtype;
269 /* It seems RFC1867 defines no Content-Type to default to
270 text/plain so we don't actually need to set this: */
271 contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
273 for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
274 if(strlen(filename) >= strlen(ctts[i].extension)) {
275 if(strequal(filename +
276 strlen(filename) - strlen(ctts[i].extension),
277 ctts[i].extension)) {
278 contenttype = ctts[i].type;
283 /* we have a contenttype by now */
287 /***************************************************************************
291 * Copies the 'source' data to a newly allocated buffer buffer (that is
292 * returned). Uses buffer_length if not null, else uses strlen to determine
293 * the length of the buffer to be copied
295 * Returns the new pointer or NULL on failure.
297 ***************************************************************************/
298 static char *memdup(const char *src, size_t buffer_length)
305 length = buffer_length;
307 length = strlen(src);
310 buffer = (char*)malloc(length+add);
312 return NULL; /* fail */
314 memcpy(buffer, src, length);
316 /* if length unknown do null termination */
318 buffer[length] = '\0';
323 /***************************************************************************
327 * Stores a formpost parameter and builds the appropriate linked list.
329 * Has two principal functionalities: using files and byte arrays as
330 * post parts. Byte arrays are either copied or just the pointer is stored
331 * (as the user requests) while for files only the filename and not the
334 * While you may have only one byte array for each name, multiple filenames
335 * are allowed (and because of this feature CURLFORM_END is needed after
336 * using CURLFORM_FILE).
340 * Simple name/value pair with copied contents:
341 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
342 * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
344 * name/value pair where only the content pointer is remembered:
345 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
346 * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
347 * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
349 * storing a filename (CONTENTTYPE is optional!):
350 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
351 * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
354 * storing multiple filenames:
355 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
356 * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
359 * CURL_FORMADD_OK on success
360 * CURL_FORMADD_MEMORY if the FormInfo allocation fails
361 * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
362 * CURL_FORMADD_NULL if a null pointer was given for a char
363 * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
364 * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
365 * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or an error)
366 * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated
367 * CURL_FORMADD_MEMORY if some allocation for string copying failed.
368 * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
370 ***************************************************************************/
373 CURLFORMcode FormAdd(struct curl_httppost **httppost,
374 struct curl_httppost **last_post,
377 FormInfo *first_form, *current_form, *form = NULL;
378 CURLFORMcode return_value = CURL_FORMADD_OK;
379 const char *prevtype = NULL;
380 struct curl_httppost *post = NULL;
381 CURLformoption option;
382 struct curl_forms *forms = NULL;
383 char *array_value=NULL; /* value read from an array */
385 /* This is a state variable, that if TRUE means that we're parsing an
386 array that we got passed to us. If FALSE we're parsing the input
387 va_list arguments. */
388 bool array_state = FALSE;
391 * We need to allocate the first struct to fill in.
393 first_form = (FormInfo *)calloc(sizeof(struct FormInfo), 1);
395 return CURL_FORMADD_MEMORY;
397 current_form = first_form;
400 * Loop through all the options set. Break if we have an error to report.
402 while (return_value == CURL_FORMADD_OK) {
404 /* first see if we have more parts of the array param */
406 /* get the upcoming option from the given array */
407 option = forms->option;
408 array_value = (char *)forms->value;
410 forms++; /* advance this to next entry */
411 if (CURLFORM_END == option) {
412 /* end of array state */
418 /* This is not array-state, get next option */
419 option = va_arg(params, CURLformoption);
420 if (CURLFORM_END == option)
427 /* we don't support an array from within an array */
428 return_value = CURL_FORMADD_ILLEGAL_ARRAY;
430 forms = va_arg(params, struct curl_forms *);
434 return_value = CURL_FORMADD_NULL;
439 * Set the Name property.
441 case CURLFORM_PTRNAME:
442 current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
443 case CURLFORM_COPYNAME:
444 if (current_form->name)
445 return_value = CURL_FORMADD_OPTION_TWICE;
447 char *name = array_state?
448 array_value:va_arg(params, char *);
450 current_form->name = name; /* store for the moment */
452 return_value = CURL_FORMADD_NULL;
455 case CURLFORM_NAMELENGTH:
456 if (current_form->namelength)
457 return_value = CURL_FORMADD_OPTION_TWICE;
459 current_form->namelength =
460 array_state?(long)array_value:va_arg(params, long);
464 * Set the contents property.
466 case CURLFORM_PTRCONTENTS:
467 current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
468 case CURLFORM_COPYCONTENTS:
469 if (current_form->value)
470 return_value = CURL_FORMADD_OPTION_TWICE;
473 array_state?array_value:va_arg(params, char *);
475 current_form->value = value; /* store for the moment */
477 return_value = CURL_FORMADD_NULL;
480 case CURLFORM_CONTENTSLENGTH:
481 if (current_form->contentslength)
482 return_value = CURL_FORMADD_OPTION_TWICE;
484 current_form->contentslength =
485 array_state?(long)array_value:va_arg(params, long);
488 /* Get contents from a given file name */
489 case CURLFORM_FILECONTENT:
490 if (current_form->flags != 0)
491 return_value = CURL_FORMADD_OPTION_TWICE;
493 char *filename = array_state?
494 array_value:va_arg(params, char *);
496 current_form->value = strdup(filename);
497 if(!current_form->value)
498 return_value = CURL_FORMADD_MEMORY;
500 current_form->flags |= HTTPPOST_READFILE;
501 current_form->value_alloc = TRUE;
505 return_value = CURL_FORMADD_NULL;
509 /* We upload a file */
512 char *filename = array_state?array_value:
513 va_arg(params, char *);
515 if (current_form->value) {
516 if (current_form->flags & HTTPPOST_FILENAME) {
518 if (!(current_form = AddFormInfo(strdup(filename),
519 NULL, current_form)))
520 return_value = CURL_FORMADD_MEMORY;
523 return_value = CURL_FORMADD_NULL;
526 return_value = CURL_FORMADD_OPTION_TWICE;
530 current_form->value = strdup(filename);
531 if(!current_form->value)
532 return_value = CURL_FORMADD_MEMORY;
534 current_form->flags |= HTTPPOST_FILENAME;
535 current_form->value_alloc = TRUE;
539 return_value = CURL_FORMADD_NULL;
544 case CURLFORM_BUFFER:
546 char *filename = array_state?array_value:
547 va_arg(params, char *);
549 if (current_form->value) {
550 if (current_form->flags & HTTPPOST_BUFFER) {
552 if (!(current_form = AddFormInfo(strdup(filename),
553 NULL, current_form)))
554 return_value = CURL_FORMADD_MEMORY;
557 return_value = CURL_FORMADD_NULL;
560 return_value = CURL_FORMADD_OPTION_TWICE;
564 current_form->value = strdup(filename);
565 if(!current_form->value)
566 return_value = CURL_FORMADD_MEMORY;
569 return_value = CURL_FORMADD_NULL;
570 current_form->flags |= HTTPPOST_BUFFER;
575 case CURLFORM_BUFFERPTR:
576 current_form->flags |= HTTPPOST_PTRBUFFER;
577 if (current_form->buffer)
578 return_value = CURL_FORMADD_OPTION_TWICE;
581 array_state?array_value:va_arg(params, char *);
583 current_form->buffer = buffer; /* store for the moment */
585 return_value = CURL_FORMADD_NULL;
589 case CURLFORM_BUFFERLENGTH:
590 if (current_form->bufferlength)
591 return_value = CURL_FORMADD_OPTION_TWICE;
593 current_form->bufferlength =
594 array_state?(long)array_value:va_arg(params, long);
597 case CURLFORM_CONTENTTYPE:
600 array_state?array_value:va_arg(params, char *);
601 if (current_form->contenttype) {
602 if (current_form->flags & HTTPPOST_FILENAME) {
604 if (!(current_form = AddFormInfo(NULL,
607 return_value = CURL_FORMADD_MEMORY;
610 return_value = CURL_FORMADD_NULL;
613 return_value = CURL_FORMADD_OPTION_TWICE;
617 current_form->contenttype = strdup(contenttype);
618 if(!current_form->contenttype)
619 return_value = CURL_FORMADD_MEMORY;
621 current_form->contenttype_alloc = TRUE;
624 return_value = CURL_FORMADD_NULL;
628 case CURLFORM_CONTENTHEADER:
630 /* this "cast increases required alignment of target type" but
631 we consider it OK anyway */
632 struct curl_slist* list = array_state?
633 (struct curl_slist*)array_value:
634 va_arg(params, struct curl_slist*);
636 if( current_form->contentheader )
637 return_value = CURL_FORMADD_OPTION_TWICE;
639 current_form->contentheader = list;
643 case CURLFORM_FILENAME:
645 char *filename = array_state?array_value:
646 va_arg(params, char *);
647 if( current_form->showfilename )
648 return_value = CURL_FORMADD_OPTION_TWICE;
650 current_form->showfilename = strdup(filename);
651 if(!current_form->showfilename)
652 return_value = CURL_FORMADD_MEMORY;
654 current_form->showfilename_alloc = TRUE;
659 return_value = CURL_FORMADD_UNKNOWN_OPTION;
663 if(CURL_FORMADD_OK == return_value) {
664 /* go through the list, check for copleteness and if everything is
665 * alright add the HttpPost item otherwise set return_value accordingly */
668 for(form = first_form;
671 if ( ((!form->name || !form->value) && !post) ||
672 ( (form->contentslength) &&
673 (form->flags & HTTPPOST_FILENAME) ) ||
674 ( (form->flags & HTTPPOST_FILENAME) &&
675 (form->flags & HTTPPOST_PTRCONTENTS) ) ||
678 (form->flags & HTTPPOST_BUFFER) &&
679 (form->flags & HTTPPOST_PTRBUFFER) ) ||
681 ( (form->flags & HTTPPOST_READFILE) &&
682 (form->flags & HTTPPOST_PTRCONTENTS) )
684 return_value = CURL_FORMADD_INCOMPLETE;
688 if ( ((form->flags & HTTPPOST_FILENAME) ||
689 (form->flags & HTTPPOST_BUFFER)) &&
690 !form->contenttype ) {
691 /* our contenttype is missing */
693 = strdup(ContentTypeForFilename(form->value, prevtype));
694 if(!form->contenttype) {
695 return_value = CURL_FORMADD_MEMORY;
698 form->contenttype_alloc = TRUE;
700 if ( !(form->flags & HTTPPOST_PTRNAME) &&
701 (form == first_form) ) {
702 /* copy name (without strdup; possibly contains null characters) */
703 form->name = memdup(form->name, form->namelength);
705 return_value = CURL_FORMADD_MEMORY;
708 form->name_alloc = TRUE;
710 if ( !(form->flags & HTTPPOST_FILENAME) &&
711 !(form->flags & HTTPPOST_READFILE) &&
712 !(form->flags & HTTPPOST_PTRCONTENTS) &&
713 !(form->flags & HTTPPOST_PTRBUFFER) ) {
714 /* copy value (without strdup; possibly contains null characters) */
715 form->value = memdup(form->value, form->contentslength);
717 return_value = CURL_FORMADD_MEMORY;
720 form->value_alloc = TRUE;
722 post = AddHttpPost(form->name, form->namelength,
723 form->value, form->contentslength,
724 form->buffer, form->bufferlength,
725 form->contenttype, form->flags,
726 form->contentheader, form->showfilename,
731 return_value = CURL_FORMADD_MEMORY;
735 if (form->contenttype)
736 prevtype = form->contenttype;
742 /* we return on error, free possibly allocated fields */
748 if(form->value_alloc)
750 if(form->contenttype_alloc)
751 free(form->contenttype);
752 if(form->showfilename_alloc)
753 free(form->showfilename);
757 /* always delete the allocated memory before returning */
759 while (form != NULL) {
760 FormInfo *delete_form;
771 * curl_formadd() is a public API to add a section to the multipart formpost.
774 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
775 struct curl_httppost **last_post,
780 va_start(arg, last_post);
781 result = FormAdd(httppost, last_post, arg);
787 * AddFormData() adds a chunk of data to the FormData linked list.
789 * size is incremented by the chunk length, unless it is NULL
791 static CURLcode AddFormData(struct FormData **formp,
797 struct FormData *newform = (struct FormData *)
798 malloc(sizeof(struct FormData));
800 return CURLE_OUT_OF_MEMORY;
801 newform->next = NULL;
803 /* we make it easier for plain strings: */
805 length = strlen((char *)line);
807 newform->line = (char *)malloc(length+1);
808 if (!newform->line) {
810 return CURLE_OUT_OF_MEMORY;
812 memcpy(newform->line, line, length);
813 newform->length = length;
814 newform->line[length]=0; /* zero terminate for easier debugging */
815 newform->type = type;
818 (*formp)->next = newform;
825 if(type == FORM_DATA)
828 /* Since this is a file to be uploaded here, add the size of the actual
830 if(!strequal("-", newform->line)) {
832 if(!stat(newform->line, &file)) {
833 *size += file.st_size;
842 * AddFormDataf() adds printf()-style formatted data to the formdata chain.
845 static CURLcode AddFormDataf(struct FormData **formp,
847 const char *fmt, ...)
852 vsnprintf(s, sizeof(s), fmt, ap);
855 return AddFormData(formp, FORM_DATA, s, 0, size);
859 * Curl_formclean() is used from http.c, this cleans a built FormData linked
862 void Curl_formclean(struct FormData *form)
864 struct FormData *next;
870 next=form->next; /* the following form line */
871 free(form->line); /* free the line */
872 free(form); /* free the struct */
874 } while((form=next)); /* continue */
878 * curl_formfree() is an external function to free up a whole form post
881 void curl_formfree(struct curl_httppost *form)
883 struct curl_httppost *next;
886 /* no form to free, just get out of this */
890 next=form->next; /* the following form line */
892 /* recurse to sub-contents */
894 curl_formfree(form->more);
896 if( !(form->flags & HTTPPOST_PTRNAME) && form->name)
897 free(form->name); /* free the name */
898 if( !(form->flags & HTTPPOST_PTRCONTENTS) && form->contents)
899 free(form->contents); /* free the contents */
900 if(form->contenttype)
901 free(form->contenttype); /* free the content type */
902 if(form->showfilename)
903 free(form->showfilename); /* free the faked file name */
904 free(form); /* free the struct */
906 } while((form=next)); /* continue */
909 #ifndef HAVE_BASENAME
911 (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
914 The basename() function shall take the pathname pointed to by path and
915 return a pointer to the final component of the pathname, deleting any
916 trailing '/' characters.
918 If the string pointed to by path consists entirely of the '/' character,
919 basename() shall return a pointer to the string "/". If the string pointed
920 to by path is exactly "//", it is implementation-defined whether '/' or "//"
923 If path is a null pointer or points to an empty string, basename() shall
924 return a pointer to the string ".".
926 The basename() function may modify the string pointed to by path, and may
927 return a pointer to static storage that may then be overwritten by a
928 subsequent call to basename().
930 The basename() function need not be reentrant. A function that is not
931 required to be reentrant is not required to be thread-safe.
934 static char *basename(char *path)
936 /* Ignore all the details above for now and make a quick and simple
937 implementaion here */
941 s1=strrchr(path, '/');
942 s2=strrchr(path, '\\');
945 path = (s1 > s2? s1 : s2)+1;
956 static char *strippath(char *fullfile)
960 filename = strdup(fullfile); /* duplicate since basename() may ruin the
961 buffer it works on */
964 base = strdup(basename(filename));
966 free(filename); /* free temporary buffer */
968 return base; /* returns an allocated string! */
972 * Curl_getFormData() converts a linked list of "meta data" into a complete
973 * (possibly huge) multipart formdata. The input list is in 'post', while the
974 * output resulting linked lists gets stored in '*finalform'. *sizep will get
975 * the total size of the whole POST.
978 CURLcode Curl_getFormData(struct FormData **finalform,
979 struct curl_httppost *post,
982 struct FormData *form = NULL;
983 struct FormData *firstform;
984 struct curl_httppost *file;
985 CURLcode result = CURLE_OK;
987 curl_off_t size=0; /* support potentially ENORMOUS formposts */
989 char *fileboundary=NULL;
990 struct curl_slist* curList;
992 *finalform=NULL; /* default form is empty */
995 return result; /* no input => no output! */
997 boundary = Curl_FormBoundary();
999 return CURLE_OUT_OF_MEMORY;
1001 /* Make the first line of the output */
1002 result = AddFormDataf(&form, NULL,
1003 "Content-Type: multipart/form-data;"
1010 /* we DO NOT include that line in the total size of the POST, since it'll be
1011 part of the header! */
1018 result = AddFormDataf(&form, &size, "\r\n");
1024 result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
1028 result = AddFormDataf(&form, &size,
1029 "Content-Disposition: form-data; name=\"");
1033 result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
1038 result = AddFormDataf(&form, &size, "\"");
1043 /* If used, this is a link to more file names, we must then do
1044 the magic to include several files with the same field name */
1046 fileboundary = Curl_FormBoundary();
1048 result = AddFormDataf(&form, &size,
1049 "\r\nContent-Type: multipart/mixed,"
1060 /* If 'showfilename' is set, that is a faked name passed on to us
1061 to use to in the formpost. If that is not set, the actually used
1062 local file name should be added. */
1065 /* if multiple-file */
1067 (!file->showfilename)?strippath(file->contents):NULL;
1069 result = AddFormDataf(&form, &size,
1070 "\r\n--%s\r\nContent-Disposition: "
1071 "attachment; filename=\"%s\"",
1073 (file->showfilename?file->showfilename:
1080 else if((post->flags & HTTPPOST_FILENAME) ||
1081 (post->flags & HTTPPOST_BUFFER)) {
1084 (!post->showfilename)?strippath(post->contents):NULL;
1086 result = AddFormDataf(&form, &size,
1087 "; filename=\"%s\"",
1088 (post->showfilename?post->showfilename:
1097 if(file->contenttype) {
1098 /* we have a specified type */
1099 result = AddFormDataf(&form, &size,
1100 "\r\nContent-Type: %s",
1106 curList = file->contentheader;
1108 /* Process the additional headers specified for this form */
1109 result = AddFormDataf( &form, &size, "\r\n%s", curList->data );
1112 curList = curList->next;
1115 Curl_formclean(firstform);
1121 /* The header Content-Transfer-Encoding: seems to confuse some receivers
1122 * (like the built-in PHP engine). While I can't see any reason why it
1123 * should, I can just as well skip this to the benefit of the users who
1124 * are using such confused receivers.
1127 if(file->contenttype &&
1128 !checkprefix("text/", file->contenttype)) {
1129 /* this is not a text content, mention our binary encoding */
1130 size += AddFormData(&form, "\r\nContent-Transfer-Encoding: binary", 0);
1134 result = AddFormDataf(&form, &size, "\r\n\r\n");
1138 if((post->flags & HTTPPOST_FILENAME) ||
1139 (post->flags & HTTPPOST_READFILE)) {
1140 /* we should include the contents from the specified file */
1143 fileread = strequal("-", file->contents)?
1144 stdin:fopen(file->contents, "rb"); /* binary read for win32 */
1147 * VMS: This only allows for stream files on VMS. Stream files are
1148 * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
1149 * every record needs to have a \n appended & 1 added to SIZE
1153 if(fileread != stdin) {
1154 /* close the file again */
1156 /* add the file name only - for later reading from this */
1157 result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
1160 /* When uploading from stdin, we can't know the size of the file,
1161 * thus must read the full file as before. We *could* use chunked
1162 * transfer-encoding, but that only works for HTTP 1.1 and we
1163 * can't be sure we work with such a server.
1167 while((nread = fread(buffer, 1, sizeof(buffer), fileread))) {
1168 result = AddFormData(&form, FORM_DATA, buffer, nread, &size);
1175 Curl_formclean(firstform);
1182 Curl_formclean(firstform);
1185 return CURLE_READ_ERROR;
1189 else if (post->flags & HTTPPOST_BUFFER) {
1190 /* include contents of buffer */
1191 result = AddFormData(&form, FORM_DATA, post->buffer,
1192 post->bufferlength, &size);
1198 /* include the contents we got */
1199 result = AddFormData(&form, FORM_DATA, post->contents,
1200 post->contentslength, &size);
1204 } while((file = file->more)); /* for each specified file for this field */
1206 Curl_formclean(firstform);
1212 /* this was a multiple-file inclusion, make a termination file
1214 result = AddFormDataf(&form, &size,
1222 } while((post=post->next)); /* for each field */
1224 Curl_formclean(firstform);
1229 /* end-boundary for everything */
1230 result = AddFormDataf(&form, &size,
1234 Curl_formclean(firstform);
1243 *finalform=firstform;
1249 * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
1250 * and resets the 'sent' counter.
1252 int Curl_FormInit(struct Form *form, struct FormData *formdata )
1255 return 1; /* error */
1257 form->data = formdata;
1264 static size_t readfromfile(struct Form *form, char *buffer, size_t size)
1268 /* this file hasn't yet been opened */
1269 form->fp = fopen(form->data->line, "rb"); /* b is for binary */
1271 return -1; /* failure */
1273 nread = fread(buffer, 1, size, form->fp);
1276 /* this is the last chunk form the file, move on */
1279 form->data = form->data->next;
1286 * Curl_FormReader() is the fread() emulation function that will be used to
1287 * deliver the formdata to the transfer loop and then sent away to the peer.
1289 size_t Curl_FormReader(char *buffer,
1298 form=(struct Form *)mydata;
1300 wantedsize = size * nitems;
1303 return 0; /* nothing, error, empty */
1305 if(form->data->type == FORM_FILE)
1306 return readfromfile(form, buffer, wantedsize);
1310 if( (form->data->length - form->sent ) > wantedsize - gotsize) {
1312 memcpy(buffer + gotsize , form->data->line + form->sent,
1313 wantedsize - gotsize);
1315 form->sent += wantedsize-gotsize;
1320 memcpy(buffer+gotsize,
1321 form->data->line + form->sent,
1322 (form->data->length - form->sent) );
1323 gotsize += form->data->length - form->sent;
1327 form->data = form->data->next; /* advance */
1329 } while(form->data && (form->data->type == FORM_DATA));
1330 /* If we got an empty line and we have more data, we proceed to the next
1331 line immediately to avoid returning zero before we've reached the end.
1332 This is the bug reported November 22 1999 on curl 6.3. (Daniel) */
1338 * Curl_formpostheader() returns the first line of the formpost, the
1339 * request-header part (which is not part of the request-body like the rest of
1342 char *Curl_formpostheader(void *formp, size_t *len)
1345 struct Form *form=(struct Form *)formp;
1348 return 0; /* nothing, ERROR! */
1350 header = form->data->line;
1351 *len = form->data->length;
1353 form->data = form->data->next; /* advance */
1360 int FormAddTest(const char * errormsg,
1361 struct curl_httppost **httppost,
1362 struct curl_httppost **last_post,
1367 va_start(arg, last_post);
1368 if ((result = FormAdd(httppost, last_post, arg)))
1369 fprintf (stderr, "ERROR doing FormAdd ret: %d action: %s\n", result,
1378 char name1[] = "simple_COPYCONTENTS";
1379 char name2[] = "COPYCONTENTS_+_CONTENTTYPE";
1380 char name3[] = "PTRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH";
1381 char name4[] = "simple_PTRCONTENTS";
1382 char name5[] = "PTRCONTENTS_+_CONTENTSLENGTH";
1383 char name6[] = "PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE";
1384 char name7[] = "FILE1_+_CONTENTTYPE";
1385 char name8[] = "FILE1_+_FILE2";
1386 char name9[] = "FILE1_+_FILE2_+_FILE3";
1387 char name10[] = "ARRAY: FILE1_+_FILE2_+_FILE3";
1388 char name11[] = "FILECONTENT";
1389 char value1[] = "value for simple COPYCONTENTS";
1390 char value2[] = "value for COPYCONTENTS + CONTENTTYPE";
1391 char value3[] = "value for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH";
1392 char value4[] = "value for simple PTRCONTENTS";
1393 char value5[] = "value for PTRCONTENTS + CONTENTSLENGTH";
1394 char value6[] = "value for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE";
1395 char value7[] = "inet_ntoa_r.h";
1396 char value8[] = "Makefile.b32.resp";
1397 char type2[] = "image/gif";
1398 char type6[] = "text/plain";
1399 char type7[] = "text/html";
1400 int name3length = strlen(name3);
1401 int value3length = strlen(value3);
1402 int value5length = strlen(value4);
1403 int value6length = strlen(value5);
1408 struct curl_httppost *httppost=NULL;
1409 struct curl_httppost *last_post=NULL;
1410 struct curl_forms forms[4];
1412 struct FormData *form;
1413 struct Form formread;
1415 if (FormAddTest("simple COPYCONTENTS test", &httppost, &last_post,
1416 CURLFORM_COPYNAME, name1, CURLFORM_COPYCONTENTS, value1,
1419 if (FormAddTest("COPYCONTENTS + CONTENTTYPE test", &httppost, &last_post,
1420 CURLFORM_COPYNAME, name2, CURLFORM_COPYCONTENTS, value2,
1421 CURLFORM_CONTENTTYPE, type2, CURLFORM_END))
1423 /* make null character at start to check that contentslength works
1427 if (FormAddTest("PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH test",
1428 &httppost, &last_post,
1429 CURLFORM_PTRNAME, name3, CURLFORM_COPYCONTENTS, value3,
1430 CURLFORM_CONTENTSLENGTH, value3length,
1431 CURLFORM_NAMELENGTH, name3length, CURLFORM_END))
1433 if (FormAddTest("simple PTRCONTENTS test", &httppost, &last_post,
1434 CURLFORM_COPYNAME, name4, CURLFORM_PTRCONTENTS, value4,
1437 /* make null character at start to check that contentslength works
1440 if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH test", &httppost, &last_post,
1441 CURLFORM_COPYNAME, name5, CURLFORM_PTRCONTENTS, value5,
1442 CURLFORM_CONTENTSLENGTH, value5length, CURLFORM_END))
1444 /* make null character at start to check that contentslength works
1447 if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE test",
1448 &httppost, &last_post,
1449 CURLFORM_COPYNAME, name6, CURLFORM_PTRCONTENTS, value6,
1450 CURLFORM_CONTENTSLENGTH, value6length,
1451 CURLFORM_CONTENTTYPE, type6, CURLFORM_END))
1453 if (FormAddTest("FILE + CONTENTTYPE test", &httppost, &last_post,
1454 CURLFORM_COPYNAME, name7, CURLFORM_FILE, value7,
1455 CURLFORM_CONTENTTYPE, type7, CURLFORM_END))
1457 if (FormAddTest("FILE1 + FILE2 test", &httppost, &last_post,
1458 CURLFORM_COPYNAME, name8, CURLFORM_FILE, value7,
1459 CURLFORM_FILE, value8, CURLFORM_END))
1461 if (FormAddTest("FILE1 + FILE2 + FILE3 test", &httppost, &last_post,
1462 CURLFORM_COPYNAME, name9, CURLFORM_FILE, value7,
1463 CURLFORM_FILE, value8, CURLFORM_FILE, value7, CURLFORM_END))
1465 forms[0].option = CURLFORM_FILE;
1466 forms[0].value = value7;
1467 forms[1].option = CURLFORM_FILE;
1468 forms[1].value = value8;
1469 forms[2].option = CURLFORM_FILE;
1470 forms[2].value = value7;
1471 forms[3].option = CURLFORM_END;
1472 if (FormAddTest("FILE1 + FILE2 + FILE3 ARRAY test", &httppost, &last_post,
1473 CURLFORM_COPYNAME, name10, CURLFORM_ARRAY, forms,
1476 if (FormAddTest("FILECONTENT test", &httppost, &last_post,
1477 CURLFORM_COPYNAME, name11, CURLFORM_FILECONTENT, value7,
1481 form=Curl_getFormData(httppost, &size);
1483 Curl_FormInit(&formread, form);
1486 nread = Curl_FormReader(buffer, 1, sizeof(buffer),
1491 fwrite(buffer, nread, 1, stdout);
1494 fprintf(stdout, "size: %d\n", size);
1496 fprintf(stdout, "\n==> %d Test(s) failed!\n", errors);
1498 fprintf(stdout, "\nAll Tests seem to have worked (please check output)\n");
1505 #else /* CURL_DISABLE_HTTP */
1506 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
1507 struct curl_httppost **last_post,
1512 return CURL_FORMADD_DISABLED;
1515 void curl_formfree(struct curl_httppost *form)
1518 /* does nothing HTTP is disabled */
1521 #endif /* CURL_DISABLE_HTTP */
1524 * Curl_FormBoundary() creates a suitable boundary string and returns an
1525 * allocated one. This is also used by SSL-code so it must be present even
1526 * if HTTP is disabled!
1528 char *Curl_FormBoundary(void)
1531 static int randomizer=0; /* this is just so that two boundaries within
1532 the same form won't be identical */
1535 static char table16[]="abcdef0123456789";
1537 retstring = (char *)malloc(BOUNDARY_LENGTH+1);
1540 return NULL; /* failed */
1542 srand(time(NULL)+randomizer++); /* seed */
1544 strcpy(retstring, "----------------------------");
1546 for(i=strlen(retstring); i<BOUNDARY_LENGTH; i++)
1547 retstring[i] = table16[rand()%16];
1549 /* 28 dashes and 12 hexadecimal digits makes 12^16 (184884258895036416)
1551 retstring[BOUNDARY_LENGTH]=0; /* zero terminate */