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 #include "formdata.h"
117 #include "strequal.h"
120 #define _MPRINTF_REPLACE /* use our functions only */
121 #include <curl/mprintf.h>
123 /* The last #include file should be: */
124 #include "memdebug.h"
126 /* What kind of Content-Type to use on un-specified files with unrecognized
128 #define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
130 #define FORM_FILE_SEPARATOR ','
131 #define FORM_TYPE_SEPARATOR ';'
133 /***************************************************************************
137 * Adds a HttpPost structure to the list, if parent_post is given becomes
138 * a subpost of parent_post instead of a direct list element.
140 * Returns newly allocated HttpPost on success and NULL if malloc failed.
142 ***************************************************************************/
143 static struct curl_httppost *
144 AddHttpPost(char * name, size_t namelength,
145 char * value, size_t contentslength,
146 char * buffer, size_t bufferlength,
149 struct curl_slist* contentHeader,
151 struct curl_httppost *parent_post,
152 struct curl_httppost **httppost,
153 struct curl_httppost **last_post)
155 struct curl_httppost *post;
156 post = (struct curl_httppost *)calloc(sizeof(struct curl_httppost), 1);
159 post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
160 post->contents = value;
161 post->contentslength = (long)contentslength;
162 post->buffer = buffer;
163 post->bufferlength = (long)bufferlength;
164 post->contenttype = contenttype;
165 post->contentheader = contentHeader;
166 post->showfilename = showfilename;
173 /* now, point our 'more' to the original 'more' */
174 post->more = parent_post->more;
176 /* then move the original 'more' to point to ourselves */
177 parent_post->more = post;
180 /* make the previous point to this */
182 (*last_post)->next = post;
191 /***************************************************************************
195 * Adds a FormInfo structure to the list presented by parent_form_info.
197 * Returns newly allocated FormInfo on success and NULL if malloc failed/
198 * parent_form_info is NULL.
200 ***************************************************************************/
201 static FormInfo * AddFormInfo(char *value,
203 FormInfo *parent_form_info)
206 form_info = (FormInfo *)malloc(sizeof(FormInfo));
208 memset(form_info, 0, sizeof(FormInfo));
210 form_info->value = value;
212 form_info->contenttype = contenttype;
213 form_info->flags = HTTPPOST_FILENAME;
218 if (parent_form_info) {
219 /* now, point our 'more' to the original 'more' */
220 form_info->more = parent_form_info->more;
222 /* then move the original 'more' to point to ourselves */
223 parent_form_info->more = form_info;
231 /***************************************************************************
233 * ContentTypeForFilename()
235 * Provides content type for filename if one of the known types (else
236 * (either the prevtype or the default is returned).
238 * Returns some valid contenttype for filename.
240 ***************************************************************************/
241 static const char * ContentTypeForFilename (const char *filename,
242 const char *prevtype)
244 const char *contenttype = NULL;
247 * No type was specified, we scan through a few well-known
248 * extensions and pick the first we match!
251 const char *extension;
254 static struct ContentType ctts[]={
255 {".gif", "image/gif"},
256 {".jpg", "image/jpeg"},
257 {".jpeg", "image/jpeg"},
258 {".txt", "text/plain"},
259 {".html", "text/html"}
263 /* default to the previously set/used! */
264 contenttype = prevtype;
266 /* It seems RFC1867 defines no Content-Type to default to
267 text/plain so we don't actually need to set this: */
268 contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
270 for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
271 if(strlen(filename) >= strlen(ctts[i].extension)) {
272 if(strequal(filename +
273 strlen(filename) - strlen(ctts[i].extension),
274 ctts[i].extension)) {
275 contenttype = ctts[i].type;
280 /* we have a contenttype by now */
284 /***************************************************************************
288 * Copies the 'source' data to a newly allocated buffer buffer (that is
289 * returned). Uses buffer_length if not null, else uses strlen to determine
290 * the length of the buffer to be copied
292 * Returns the new pointer or NULL on failure.
294 ***************************************************************************/
295 static char *memdup(const char *src, size_t buffer_length)
302 length = buffer_length;
304 length = strlen(src);
307 buffer = (char*)malloc(length+add);
309 return NULL; /* fail */
311 memcpy(buffer, src, length);
313 /* if length unknown do null termination */
315 buffer[length] = '\0';
320 /***************************************************************************
324 * Stores a formpost parameter and builds the appropriate linked list.
326 * Has two principal functionalities: using files and byte arrays as
327 * post parts. Byte arrays are either copied or just the pointer is stored
328 * (as the user requests) while for files only the filename and not the
331 * While you may have only one byte array for each name, multiple filenames
332 * are allowed (and because of this feature CURLFORM_END is needed after
333 * using CURLFORM_FILE).
337 * Simple name/value pair with copied contents:
338 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
339 * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
341 * name/value pair where only the content pointer is remembered:
342 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
343 * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
344 * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
346 * storing a filename (CONTENTTYPE is optional!):
347 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
348 * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
351 * storing multiple filenames:
352 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
353 * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
356 * CURL_FORMADD_OK on success
357 * CURL_FORMADD_MEMORY if the FormInfo allocation fails
358 * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
359 * CURL_FORMADD_NULL if a null pointer was given for a char
360 * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
361 * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
362 * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or an error)
363 * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated
364 * CURL_FORMADD_MEMORY if some allocation for string copying failed.
365 * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
367 ***************************************************************************/
370 CURLFORMcode FormAdd(struct curl_httppost **httppost,
371 struct curl_httppost **last_post,
374 FormInfo *first_form, *current_form, *form = NULL;
375 CURLFORMcode return_value = CURL_FORMADD_OK;
376 const char *prevtype = NULL;
377 struct curl_httppost *post = NULL;
378 CURLformoption option;
379 struct curl_forms *forms = NULL;
380 char *array_value=NULL; /* value read from an array */
382 /* This is a state variable, that if TRUE means that we're parsing an
383 array that we got passed to us. If FALSE we're parsing the input
384 va_list arguments. */
385 bool array_state = FALSE;
388 * We need to allocate the first struct to fill in.
390 first_form = (FormInfo *)calloc(sizeof(struct FormInfo), 1);
392 return CURL_FORMADD_MEMORY;
394 current_form = first_form;
397 * Loop through all the options set. Break if we have an error to report.
399 while (return_value == CURL_FORMADD_OK) {
401 /* first see if we have more parts of the array param */
403 /* get the upcoming option from the given array */
404 option = forms->option;
405 array_value = (char *)forms->value;
407 forms++; /* advance this to next entry */
408 if (CURLFORM_END == option) {
409 /* end of array state */
415 /* This is not array-state, get next option */
416 option = va_arg(params, CURLformoption);
417 if (CURLFORM_END == option)
424 /* we don't support an array from within an array */
425 return_value = CURL_FORMADD_ILLEGAL_ARRAY;
427 forms = va_arg(params, struct curl_forms *);
431 return_value = CURL_FORMADD_NULL;
436 * Set the Name property.
438 case CURLFORM_PTRNAME:
439 current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
440 case CURLFORM_COPYNAME:
441 if (current_form->name)
442 return_value = CURL_FORMADD_OPTION_TWICE;
444 char *name = array_state?
445 array_value:va_arg(params, char *);
447 current_form->name = name; /* store for the moment */
449 return_value = CURL_FORMADD_NULL;
452 case CURLFORM_NAMELENGTH:
453 if (current_form->namelength)
454 return_value = CURL_FORMADD_OPTION_TWICE;
456 current_form->namelength =
457 array_state?(long)array_value:va_arg(params, long);
461 * Set the contents property.
463 case CURLFORM_PTRCONTENTS:
464 current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
465 case CURLFORM_COPYCONTENTS:
466 if (current_form->value)
467 return_value = CURL_FORMADD_OPTION_TWICE;
470 array_state?array_value:va_arg(params, char *);
472 current_form->value = value; /* store for the moment */
474 return_value = CURL_FORMADD_NULL;
477 case CURLFORM_CONTENTSLENGTH:
478 if (current_form->contentslength)
479 return_value = CURL_FORMADD_OPTION_TWICE;
481 current_form->contentslength =
482 array_state?(long)array_value:va_arg(params, long);
485 /* Get contents from a given file name */
486 case CURLFORM_FILECONTENT:
487 if (current_form->flags != 0)
488 return_value = CURL_FORMADD_OPTION_TWICE;
490 char *filename = array_state?
491 array_value:va_arg(params, char *);
493 current_form->value = strdup(filename);
494 if(!current_form->value)
495 return_value = CURL_FORMADD_MEMORY;
497 current_form->flags |= HTTPPOST_READFILE;
498 current_form->value_alloc = TRUE;
502 return_value = CURL_FORMADD_NULL;
506 /* We upload a file */
509 char *filename = array_state?array_value:
510 va_arg(params, char *);
512 if (current_form->value) {
513 if (current_form->flags & HTTPPOST_FILENAME) {
515 if (!(current_form = AddFormInfo(strdup(filename),
516 NULL, current_form)))
517 return_value = CURL_FORMADD_MEMORY;
520 return_value = CURL_FORMADD_NULL;
523 return_value = CURL_FORMADD_OPTION_TWICE;
527 current_form->value = strdup(filename);
528 if(!current_form->value)
529 return_value = CURL_FORMADD_MEMORY;
531 current_form->flags |= HTTPPOST_FILENAME;
532 current_form->value_alloc = TRUE;
536 return_value = CURL_FORMADD_NULL;
541 case CURLFORM_BUFFER:
543 char *filename = array_state?array_value:
544 va_arg(params, char *);
546 if (current_form->value) {
547 if (current_form->flags & HTTPPOST_BUFFER) {
549 if (!(current_form = AddFormInfo(strdup(filename),
550 NULL, current_form)))
551 return_value = CURL_FORMADD_MEMORY;
554 return_value = CURL_FORMADD_NULL;
557 return_value = CURL_FORMADD_OPTION_TWICE;
561 current_form->value = strdup(filename);
562 if(!current_form->value)
563 return_value = CURL_FORMADD_MEMORY;
566 return_value = CURL_FORMADD_NULL;
567 current_form->flags |= HTTPPOST_BUFFER;
572 case CURLFORM_BUFFERPTR:
573 current_form->flags |= HTTPPOST_PTRBUFFER;
574 if (current_form->buffer)
575 return_value = CURL_FORMADD_OPTION_TWICE;
578 array_state?array_value:va_arg(params, char *);
580 current_form->buffer = buffer; /* store for the moment */
582 return_value = CURL_FORMADD_NULL;
586 case CURLFORM_BUFFERLENGTH:
587 if (current_form->bufferlength)
588 return_value = CURL_FORMADD_OPTION_TWICE;
590 current_form->bufferlength =
591 array_state?(long)array_value:va_arg(params, long);
594 case CURLFORM_CONTENTTYPE:
597 array_state?array_value:va_arg(params, char *);
598 if (current_form->contenttype) {
599 if (current_form->flags & HTTPPOST_FILENAME) {
601 if (!(current_form = AddFormInfo(NULL,
604 return_value = CURL_FORMADD_MEMORY;
607 return_value = CURL_FORMADD_NULL;
610 return_value = CURL_FORMADD_OPTION_TWICE;
614 current_form->contenttype = strdup(contenttype);
615 if(!current_form->contenttype)
616 return_value = CURL_FORMADD_MEMORY;
618 current_form->contenttype_alloc = TRUE;
621 return_value = CURL_FORMADD_NULL;
625 case CURLFORM_CONTENTHEADER:
627 /* this "cast increases required alignment of target type" but
628 we consider it OK anyway */
629 struct curl_slist* list = array_state?
630 (struct curl_slist*)array_value:
631 va_arg(params, struct curl_slist*);
633 if( current_form->contentheader )
634 return_value = CURL_FORMADD_OPTION_TWICE;
636 current_form->contentheader = list;
640 case CURLFORM_FILENAME:
642 char *filename = array_state?array_value:
643 va_arg(params, char *);
644 if( current_form->showfilename )
645 return_value = CURL_FORMADD_OPTION_TWICE;
647 current_form->showfilename = strdup(filename);
648 if(!current_form->showfilename)
649 return_value = CURL_FORMADD_MEMORY;
651 current_form->showfilename_alloc = TRUE;
656 return_value = CURL_FORMADD_UNKNOWN_OPTION;
660 if(CURL_FORMADD_OK == return_value) {
661 /* go through the list, check for copleteness and if everything is
662 * alright add the HttpPost item otherwise set return_value accordingly */
665 for(form = first_form;
668 if ( ((!form->name || !form->value) && !post) ||
669 ( (form->contentslength) &&
670 (form->flags & HTTPPOST_FILENAME) ) ||
671 ( (form->flags & HTTPPOST_FILENAME) &&
672 (form->flags & HTTPPOST_PTRCONTENTS) ) ||
675 (form->flags & HTTPPOST_BUFFER) &&
676 (form->flags & HTTPPOST_PTRBUFFER) ) ||
678 ( (form->flags & HTTPPOST_READFILE) &&
679 (form->flags & HTTPPOST_PTRCONTENTS) )
681 return_value = CURL_FORMADD_INCOMPLETE;
685 if ( ((form->flags & HTTPPOST_FILENAME) ||
686 (form->flags & HTTPPOST_BUFFER)) &&
687 !form->contenttype ) {
688 /* our contenttype is missing */
690 = strdup(ContentTypeForFilename(form->value, prevtype));
691 if(!form->contenttype) {
692 return_value = CURL_FORMADD_MEMORY;
695 form->contenttype_alloc = TRUE;
697 if ( !(form->flags & HTTPPOST_PTRNAME) &&
698 (form == first_form) ) {
699 /* copy name (without strdup; possibly contains null characters) */
700 form->name = memdup(form->name, form->namelength);
702 return_value = CURL_FORMADD_MEMORY;
705 form->name_alloc = TRUE;
707 if ( !(form->flags & HTTPPOST_FILENAME) &&
708 !(form->flags & HTTPPOST_READFILE) &&
709 !(form->flags & HTTPPOST_PTRCONTENTS) &&
710 !(form->flags & HTTPPOST_PTRBUFFER) ) {
711 /* copy value (without strdup; possibly contains null characters) */
712 form->value = memdup(form->value, form->contentslength);
714 return_value = CURL_FORMADD_MEMORY;
717 form->value_alloc = TRUE;
719 post = AddHttpPost(form->name, form->namelength,
720 form->value, form->contentslength,
721 form->buffer, form->bufferlength,
722 form->contenttype, form->flags,
723 form->contentheader, form->showfilename,
728 return_value = CURL_FORMADD_MEMORY;
732 if (form->contenttype)
733 prevtype = form->contenttype;
739 /* we return on error, free possibly allocated fields */
745 if(form->value_alloc)
747 if(form->contenttype_alloc)
748 free(form->contenttype);
749 if(form->showfilename_alloc)
750 free(form->showfilename);
754 /* always delete the allocated memory before returning */
756 while (form != NULL) {
757 FormInfo *delete_form;
768 * curl_formadd() is a public API to add a section to the multipart formpost.
771 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
772 struct curl_httppost **last_post,
777 va_start(arg, last_post);
778 result = FormAdd(httppost, last_post, arg);
784 * AddFormData() adds a chunk of data to the FormData linked list.
786 * size is incremented by the chunk length, unless it is NULL
788 static CURLcode AddFormData(struct FormData **formp,
794 struct FormData *newform = (struct FormData *)
795 malloc(sizeof(struct FormData));
797 return CURLE_OUT_OF_MEMORY;
798 newform->next = NULL;
800 /* we make it easier for plain strings: */
802 length = strlen((char *)line);
804 newform->line = (char *)malloc(length+1);
805 if (!newform->line) {
807 return CURLE_OUT_OF_MEMORY;
809 memcpy(newform->line, line, length);
810 newform->length = length;
811 newform->line[length]=0; /* zero terminate for easier debugging */
812 newform->type = type;
815 (*formp)->next = newform;
822 if(type == FORM_DATA)
825 /* Since this is a file to be uploaded here, add the size of the actual
827 if(!strequal("-", newform->line)) {
829 if(!stat(newform->line, &file)) {
830 *size += file.st_size;
839 * AddFormDataf() adds printf()-style formatted data to the formdata chain.
842 static CURLcode AddFormDataf(struct FormData **formp,
844 const char *fmt, ...)
849 vsprintf(s, fmt, ap);
852 return AddFormData(formp, FORM_DATA, s, 0, size);
856 * Curl_formclean() is used from http.c, this cleans a built FormData linked
859 void Curl_formclean(struct FormData *form)
861 struct FormData *next;
867 next=form->next; /* the following form line */
868 free(form->line); /* free the line */
869 free(form); /* free the struct */
871 } while((form=next)); /* continue */
875 * curl_formfree() is an external function to free up a whole form post
878 void curl_formfree(struct curl_httppost *form)
880 struct curl_httppost *next;
883 /* no form to free, just get out of this */
887 next=form->next; /* the following form line */
889 /* recurse to sub-contents */
891 curl_formfree(form->more);
893 if( !(form->flags & HTTPPOST_PTRNAME) && form->name)
894 free(form->name); /* free the name */
895 if( !(form->flags & HTTPPOST_PTRCONTENTS) && form->contents)
896 free(form->contents); /* free the contents */
897 if(form->contenttype)
898 free(form->contenttype); /* free the content type */
899 if(form->showfilename)
900 free(form->showfilename); /* free the faked file name */
901 free(form); /* free the struct */
903 } while((form=next)); /* continue */
907 * Curl_getFormData() converts a linked list of "meta data" into a complete
908 * (possibly huge) multipart formdata. The input list is in 'post', while the
909 * output resulting linked lists gets stored in '*finalform'. *sizep will get
910 * the total size of the whole POST.
913 CURLcode Curl_getFormData(struct FormData **finalform,
914 struct curl_httppost *post,
917 struct FormData *form = NULL;
918 struct FormData *firstform;
919 struct curl_httppost *file;
920 CURLcode result = CURLE_OK;
922 curl_off_t size=0; /* support potentially ENORMOUS formposts */
924 char *fileboundary=NULL;
925 struct curl_slist* curList;
927 *finalform=NULL; /* default form is empty */
930 return result; /* no input => no output! */
932 boundary = Curl_FormBoundary();
934 return CURLE_OUT_OF_MEMORY;
936 /* Make the first line of the output */
937 result = AddFormDataf(&form, NULL,
938 "Content-Type: multipart/form-data;"
945 /* we DO NOT include that line in the total size of the POST, since it'll be
946 part of the header! */
953 result = AddFormDataf(&form, &size, "\r\n");
959 result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
963 result = AddFormDataf(&form, &size,
964 "Content-Disposition: form-data; name=\"");
968 result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
973 result = AddFormDataf(&form, &size, "\"");
978 /* If used, this is a link to more file names, we must then do
979 the magic to include several files with the same field name */
981 fileboundary = Curl_FormBoundary();
983 result = AddFormDataf(&form, &size,
984 "\r\nContent-Type: multipart/mixed,"
995 /* If 'showfilename' is set, that is a faked name passed on to us
996 to use to in the formpost. If that is not set, the actually used
997 local file name should be added. */
1000 /* if multiple-file */
1001 result = AddFormDataf(&form, &size,
1002 "\r\n--%s\r\nContent-Disposition: "
1003 "attachment; filename=\"%s\"",
1005 (file->showfilename?file->showfilename:
1010 else if((post->flags & HTTPPOST_FILENAME) ||
1011 (post->flags & HTTPPOST_BUFFER)) {
1013 result = AddFormDataf(&form, &size,
1014 "; filename=\"%s\"",
1015 (post->showfilename?post->showfilename:
1021 if(file->contenttype) {
1022 /* we have a specified type */
1023 result = AddFormDataf(&form, &size,
1024 "\r\nContent-Type: %s",
1030 curList = file->contentheader;
1032 /* Process the additional headers specified for this form */
1033 result = AddFormDataf( &form, &size, "\r\n%s", curList->data );
1036 curList = curList->next;
1039 Curl_formclean(firstform);
1045 /* The header Content-Transfer-Encoding: seems to confuse some receivers
1046 * (like the built-in PHP engine). While I can't see any reason why it
1047 * should, I can just as well skip this to the benefit of the users who
1048 * are using such confused receivers.
1051 if(file->contenttype &&
1052 !checkprefix("text/", file->contenttype)) {
1053 /* this is not a text content, mention our binary encoding */
1054 size += AddFormData(&form, "\r\nContent-Transfer-Encoding: binary", 0);
1058 result = AddFormDataf(&form, &size, "\r\n\r\n");
1062 if((post->flags & HTTPPOST_FILENAME) ||
1063 (post->flags & HTTPPOST_READFILE)) {
1064 /* we should include the contents from the specified file */
1067 fileread = strequal("-", file->contents)?
1068 stdin:fopen(file->contents, "rb"); /* binary read for win32 */
1071 * VMS: This only allows for stream files on VMS. Stream files are
1072 * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
1073 * every record needs to have a \n appended & 1 added to SIZE
1077 if(fileread != stdin) {
1078 /* close the file again */
1080 /* add the file name only - for later reading from this */
1081 result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
1084 /* When uploading from stdin, we can't know the size of the file,
1085 * thus must read the full file as before. We *could* use chunked
1086 * transfer-encoding, but that only works for HTTP 1.1 and we
1087 * can't be sure we work with such a server.
1091 while((nread = fread(buffer, 1, sizeof(buffer), fileread))) {
1092 result = AddFormData(&form, FORM_DATA, buffer, nread, &size);
1099 Curl_formclean(firstform);
1106 Curl_formclean(firstform);
1109 return CURLE_READ_ERROR;
1113 else if (post->flags & HTTPPOST_BUFFER) {
1114 /* include contents of buffer */
1115 result = AddFormData(&form, FORM_DATA, post->buffer,
1116 post->bufferlength, &size);
1122 /* include the contents we got */
1123 result = AddFormData(&form, FORM_DATA, post->contents,
1124 post->contentslength, &size);
1128 } while((file = file->more)); /* for each specified file for this field */
1130 Curl_formclean(firstform);
1136 /* this was a multiple-file inclusion, make a termination file
1138 result = AddFormDataf(&form, &size,
1146 } while((post=post->next)); /* for each field */
1148 Curl_formclean(firstform);
1153 /* end-boundary for everything */
1154 result = AddFormDataf(&form, &size,
1158 Curl_formclean(firstform);
1167 *finalform=firstform;
1173 * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
1174 * and resets the 'sent' counter.
1176 int Curl_FormInit(struct Form *form, struct FormData *formdata )
1179 return 1; /* error */
1181 form->data = formdata;
1188 static size_t readfromfile(struct Form *form, char *buffer, size_t size)
1192 /* this file hasn't yet been opened */
1193 form->fp = fopen(form->data->line, "rb"); /* b is for binary */
1195 return -1; /* failure */
1197 nread = fread(buffer, 1, size, form->fp);
1200 /* this is the last chunk form the file, move on */
1203 form->data = form->data->next;
1210 * Curl_FormReader() is the fread() emulation function that will be used to
1211 * deliver the formdata to the transfer loop and then sent away to the peer.
1213 size_t Curl_FormReader(char *buffer,
1222 form=(struct Form *)mydata;
1224 wantedsize = size * nitems;
1227 return 0; /* nothing, error, empty */
1229 if(form->data->type == FORM_FILE)
1230 return readfromfile(form, buffer, wantedsize);
1234 if( (form->data->length - form->sent ) > wantedsize - gotsize) {
1236 memcpy(buffer + gotsize , form->data->line + form->sent,
1237 wantedsize - gotsize);
1239 form->sent += wantedsize-gotsize;
1244 memcpy(buffer+gotsize,
1245 form->data->line + form->sent,
1246 (form->data->length - form->sent) );
1247 gotsize += form->data->length - form->sent;
1251 form->data = form->data->next; /* advance */
1253 } while(form->data && (form->data->type == FORM_DATA));
1254 /* If we got an empty line and we have more data, we proceed to the next
1255 line immediately to avoid returning zero before we've reached the end.
1256 This is the bug reported November 22 1999 on curl 6.3. (Daniel) */
1262 * Curl_formpostheader() returns the first line of the formpost, the
1263 * request-header part (which is not part of the request-body like the rest of
1266 char *Curl_formpostheader(void *formp, size_t *len)
1269 struct Form *form=(struct Form *)formp;
1272 return 0; /* nothing, ERROR! */
1274 header = form->data->line;
1275 *len = form->data->length;
1277 form->data = form->data->next; /* advance */
1284 int FormAddTest(const char * errormsg,
1285 struct curl_httppost **httppost,
1286 struct curl_httppost **last_post,
1291 va_start(arg, last_post);
1292 if ((result = FormAdd(httppost, last_post, arg)))
1293 fprintf (stderr, "ERROR doing FormAdd ret: %d action: %s\n", result,
1302 char name1[] = "simple_COPYCONTENTS";
1303 char name2[] = "COPYCONTENTS_+_CONTENTTYPE";
1304 char name3[] = "PTRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH";
1305 char name4[] = "simple_PTRCONTENTS";
1306 char name5[] = "PTRCONTENTS_+_CONTENTSLENGTH";
1307 char name6[] = "PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE";
1308 char name7[] = "FILE1_+_CONTENTTYPE";
1309 char name8[] = "FILE1_+_FILE2";
1310 char name9[] = "FILE1_+_FILE2_+_FILE3";
1311 char name10[] = "ARRAY: FILE1_+_FILE2_+_FILE3";
1312 char name11[] = "FILECONTENT";
1313 char value1[] = "value for simple COPYCONTENTS";
1314 char value2[] = "value for COPYCONTENTS + CONTENTTYPE";
1315 char value3[] = "value for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH";
1316 char value4[] = "value for simple PTRCONTENTS";
1317 char value5[] = "value for PTRCONTENTS + CONTENTSLENGTH";
1318 char value6[] = "value for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE";
1319 char value7[] = "inet_ntoa_r.h";
1320 char value8[] = "Makefile.b32.resp";
1321 char type2[] = "image/gif";
1322 char type6[] = "text/plain";
1323 char type7[] = "text/html";
1324 int name3length = strlen(name3);
1325 int value3length = strlen(value3);
1326 int value5length = strlen(value4);
1327 int value6length = strlen(value5);
1332 struct curl_httppost *httppost=NULL;
1333 struct curl_httppost *last_post=NULL;
1334 struct curl_forms forms[4];
1336 struct FormData *form;
1337 struct Form formread;
1339 if (FormAddTest("simple COPYCONTENTS test", &httppost, &last_post,
1340 CURLFORM_COPYNAME, name1, CURLFORM_COPYCONTENTS, value1,
1343 if (FormAddTest("COPYCONTENTS + CONTENTTYPE test", &httppost, &last_post,
1344 CURLFORM_COPYNAME, name2, CURLFORM_COPYCONTENTS, value2,
1345 CURLFORM_CONTENTTYPE, type2, CURLFORM_END))
1347 /* make null character at start to check that contentslength works
1351 if (FormAddTest("PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH test",
1352 &httppost, &last_post,
1353 CURLFORM_PTRNAME, name3, CURLFORM_COPYCONTENTS, value3,
1354 CURLFORM_CONTENTSLENGTH, value3length,
1355 CURLFORM_NAMELENGTH, name3length, CURLFORM_END))
1357 if (FormAddTest("simple PTRCONTENTS test", &httppost, &last_post,
1358 CURLFORM_COPYNAME, name4, CURLFORM_PTRCONTENTS, value4,
1361 /* make null character at start to check that contentslength works
1364 if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH test", &httppost, &last_post,
1365 CURLFORM_COPYNAME, name5, CURLFORM_PTRCONTENTS, value5,
1366 CURLFORM_CONTENTSLENGTH, value5length, CURLFORM_END))
1368 /* make null character at start to check that contentslength works
1371 if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE test",
1372 &httppost, &last_post,
1373 CURLFORM_COPYNAME, name6, CURLFORM_PTRCONTENTS, value6,
1374 CURLFORM_CONTENTSLENGTH, value6length,
1375 CURLFORM_CONTENTTYPE, type6, CURLFORM_END))
1377 if (FormAddTest("FILE + CONTENTTYPE test", &httppost, &last_post,
1378 CURLFORM_COPYNAME, name7, CURLFORM_FILE, value7,
1379 CURLFORM_CONTENTTYPE, type7, CURLFORM_END))
1381 if (FormAddTest("FILE1 + FILE2 test", &httppost, &last_post,
1382 CURLFORM_COPYNAME, name8, CURLFORM_FILE, value7,
1383 CURLFORM_FILE, value8, CURLFORM_END))
1385 if (FormAddTest("FILE1 + FILE2 + FILE3 test", &httppost, &last_post,
1386 CURLFORM_COPYNAME, name9, CURLFORM_FILE, value7,
1387 CURLFORM_FILE, value8, CURLFORM_FILE, value7, CURLFORM_END))
1389 forms[0].option = CURLFORM_FILE;
1390 forms[0].value = value7;
1391 forms[1].option = CURLFORM_FILE;
1392 forms[1].value = value8;
1393 forms[2].option = CURLFORM_FILE;
1394 forms[2].value = value7;
1395 forms[3].option = CURLFORM_END;
1396 if (FormAddTest("FILE1 + FILE2 + FILE3 ARRAY test", &httppost, &last_post,
1397 CURLFORM_COPYNAME, name10, CURLFORM_ARRAY, forms,
1400 if (FormAddTest("FILECONTENT test", &httppost, &last_post,
1401 CURLFORM_COPYNAME, name11, CURLFORM_FILECONTENT, value7,
1405 form=Curl_getFormData(httppost, &size);
1407 Curl_FormInit(&formread, form);
1410 nread = Curl_FormReader(buffer, 1, sizeof(buffer),
1415 fwrite(buffer, nread, 1, stdout);
1418 fprintf(stdout, "size: %d\n", size);
1420 fprintf(stdout, "\n==> %d Test(s) failed!\n", errors);
1422 fprintf(stdout, "\nAll Tests seem to have worked (please check output)\n");
1429 #else /* CURL_DISABLE_HTTP */
1430 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
1431 struct curl_httppost **last_post,
1436 return CURL_FORMADD_DISABLED;
1439 void curl_formfree(struct curl_httppost *form)
1442 /* does nothing HTTP is disabled */
1445 #endif /* CURL_DISABLE_HTTP */
1448 * Curl_FormBoundary() creates a suitable boundary string and returns an
1449 * allocated one. This is also used by SSL-code so it must be present even
1450 * if HTTP is disabled!
1452 char *Curl_FormBoundary(void)
1455 static int randomizer=0; /* this is just so that two boundaries within
1456 the same form won't be identical */
1459 static char table16[]="abcdef0123456789";
1461 retstring = (char *)malloc(BOUNDARY_LENGTH+1);
1464 return NULL; /* failed */
1466 srand(time(NULL)+randomizer++); /* seed */
1468 strcpy(retstring, "----------------------------");
1470 for(i=strlen(retstring); i<BOUNDARY_LENGTH; i++)
1471 retstring[i] = table16[rand()%16];
1473 /* 28 dashes and 12 hexadecimal digits makes 12^16 (184884258895036416)
1475 retstring[BOUNDARY_LENGTH]=0; /* zero terminate */