1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2007, 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 -DCURLDEBUG -o formdata \
28 -I../include formdata.c strequal.c memdebug.c mprintf.c strerror.c
30 (depending on circumstances you may need further externals added)
32 run the 'formdata' executable the output should end with:
33 All Tests seem to have worked ...
34 and the following parts should be there:
36 Content-Disposition: form-data; name="simple_COPYCONTENTS"
37 value for simple COPYCONTENTS
39 Content-Disposition: form-data; name="COPYCONTENTS_+_CONTENTTYPE"
40 Content-Type: image/gif
41 value for COPYCONTENTS + CONTENTTYPE
43 Content-Disposition: form-data; name="PRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH"
44 vlue for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH
45 (or you might see P^@RNAME and v^@lue at the start)
47 Content-Disposition: form-data; name="simple_PTRCONTENTS"
48 value for simple PTRCONTENTS
50 Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH"
51 vlue for PTRCONTENTS + CONTENTSLENGTH
52 (or you might see v^@lue at the start)
54 Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE"
55 Content-Type: application/octet-stream
56 vlue for PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE
57 (or you might see v^@lue at the start)
59 Content-Disposition: form-data; name="FILE1_+_CONTENTTYPE"; filename="inet_ntoa_r.h"
60 Content-Type: text/html
63 Content-Disposition: form-data; name="FILE1_+_FILE2"
64 Content-Type: multipart/mixed, boundary=curlz1s0dkticx49MV1KGcYP5cvfSsz
66 Content-Disposition: attachment; filename="inet_ntoa_r.h"
67 Content-Type: application/octet-stream
69 Content-Disposition: attachment; filename="Makefile.b32"
70 Content-Type: application/octet-stream
73 Content-Disposition: form-data; name="FILE1_+_FILE2_+_FILE3"
74 Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1
76 Content-Disposition: attachment; filename="inet_ntoa_r.h"
77 Content-Type: application/octet-stream
79 Content-Disposition: attachment; filename="Makefile.b32"
80 Content-Type: application/octet-stream
82 Content-Disposition: attachment; filename="inet_ntoa_r.h"
83 Content-Type: application/octet-stream
87 Content-Disposition: form-data; name="ARRAY: FILE1_+_FILE2_+_FILE3"
88 Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1
90 Content-Disposition: attachment; filename="inet_ntoa_r.h"
91 Content-Type: application/octet-stream
93 Content-Disposition: attachment; filename="Makefile.b32"
94 Content-Type: application/octet-stream
96 Content-Disposition: attachment; filename="inet_ntoa_r.h"
97 Content-Type: application/octet-stream
100 Content-Disposition: form-data; name="FILECONTENT"
106 #include <curl/curl.h>
108 /* Length of the random boundary string. */
109 #define BOUNDARY_LENGTH 40
111 #if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
118 #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
121 #include "urldata.h" /* for struct SessionHandle */
122 #include "easyif.h" /* for Curl_convert_... prototypes */
123 #include "formdata.h"
124 #include "strequal.h"
127 #define _MPRINTF_REPLACE /* use our functions only */
128 #include <curl/mprintf.h>
130 /* The last #include file should be: */
131 #include "memdebug.h"
133 #endif /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */
135 #ifndef CURL_DISABLE_HTTP
137 #if defined(HAVE_BASENAME) && defined(NEED_BASENAME_PROTO)
138 /* This system has a basename() but no prototype for it! */
139 char *basename(char *path);
142 static size_t readfromfile(struct Form *form, char *buffer, size_t size);
144 /* What kind of Content-Type to use on un-specified files with unrecognized
146 #define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
148 #define FORM_FILE_SEPARATOR ','
149 #define FORM_TYPE_SEPARATOR ';'
151 /***************************************************************************
155 * Adds a HttpPost structure to the list, if parent_post is given becomes
156 * a subpost of parent_post instead of a direct list element.
158 * Returns newly allocated HttpPost on success and NULL if malloc failed.
160 ***************************************************************************/
161 static struct curl_httppost *
162 AddHttpPost(char * name, size_t namelength,
163 char * value, size_t contentslength,
164 char * buffer, size_t bufferlength,
167 struct curl_slist* contentHeader,
169 struct curl_httppost *parent_post,
170 struct curl_httppost **httppost,
171 struct curl_httppost **last_post)
173 struct curl_httppost *post;
174 post = (struct curl_httppost *)calloc(sizeof(struct curl_httppost), 1);
177 post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
178 post->contents = value;
179 post->contentslength = (long)contentslength;
180 post->buffer = buffer;
181 post->bufferlength = (long)bufferlength;
182 post->contenttype = contenttype;
183 post->contentheader = contentHeader;
184 post->showfilename = showfilename;
191 /* now, point our 'more' to the original 'more' */
192 post->more = parent_post->more;
194 /* then move the original 'more' to point to ourselves */
195 parent_post->more = post;
198 /* make the previous point to this */
200 (*last_post)->next = post;
209 /***************************************************************************
213 * Adds a FormInfo structure to the list presented by parent_form_info.
215 * Returns newly allocated FormInfo on success and NULL if malloc failed/
216 * parent_form_info is NULL.
218 ***************************************************************************/
219 static FormInfo * AddFormInfo(char *value,
221 FormInfo *parent_form_info)
224 form_info = (FormInfo *)malloc(sizeof(FormInfo));
226 memset(form_info, 0, sizeof(FormInfo));
228 form_info->value = value;
230 form_info->contenttype = contenttype;
231 form_info->flags = HTTPPOST_FILENAME;
236 if (parent_form_info) {
237 /* now, point our 'more' to the original 'more' */
238 form_info->more = parent_form_info->more;
240 /* then move the original 'more' to point to ourselves */
241 parent_form_info->more = form_info;
249 /***************************************************************************
251 * ContentTypeForFilename()
253 * Provides content type for filename if one of the known types (else
254 * (either the prevtype or the default is returned).
256 * Returns some valid contenttype for filename.
258 ***************************************************************************/
259 static const char * ContentTypeForFilename (const char *filename,
260 const char *prevtype)
262 const char *contenttype = NULL;
265 * No type was specified, we scan through a few well-known
266 * extensions and pick the first we match!
269 const char *extension;
272 static const struct ContentType ctts[]={
273 {".gif", "image/gif"},
274 {".jpg", "image/jpeg"},
275 {".jpeg", "image/jpeg"},
276 {".txt", "text/plain"},
277 {".html", "text/html"}
281 /* default to the previously set/used! */
282 contenttype = prevtype;
284 contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
286 if(filename) { /* in case a NULL was passed in */
287 for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
288 if(strlen(filename) >= strlen(ctts[i].extension)) {
289 if(strequal(filename +
290 strlen(filename) - strlen(ctts[i].extension),
291 ctts[i].extension)) {
292 contenttype = ctts[i].type;
298 /* we have a contenttype by now */
302 /***************************************************************************
306 * Copies the 'source' data to a newly allocated buffer buffer (that is
307 * returned). Uses buffer_length if not null, else uses strlen to determine
308 * the length of the buffer to be copied
310 * Returns the new pointer or NULL on failure.
312 ***************************************************************************/
313 static char *memdup(const char *src, size_t buffer_length)
320 length = buffer_length;
322 length = strlen(src);
326 /* no length and a NULL src pointer! */
327 return strdup((char *)"");
329 buffer = (char*)malloc(length+add);
331 return NULL; /* fail */
333 memcpy(buffer, src, length);
335 /* if length unknown do null termination */
337 buffer[length] = '\0';
342 /***************************************************************************
346 * Stores a formpost parameter and builds the appropriate linked list.
348 * Has two principal functionalities: using files and byte arrays as
349 * post parts. Byte arrays are either copied or just the pointer is stored
350 * (as the user requests) while for files only the filename and not the
353 * While you may have only one byte array for each name, multiple filenames
354 * are allowed (and because of this feature CURLFORM_END is needed after
355 * using CURLFORM_FILE).
359 * Simple name/value pair with copied contents:
360 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
361 * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
363 * name/value pair where only the content pointer is remembered:
364 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
365 * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
366 * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
368 * storing a filename (CONTENTTYPE is optional!):
369 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
370 * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
373 * storing multiple filenames:
374 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
375 * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
378 * CURL_FORMADD_OK on success
379 * CURL_FORMADD_MEMORY if the FormInfo allocation fails
380 * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
381 * CURL_FORMADD_NULL if a null pointer was given for a char
382 * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
383 * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
384 * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or an error)
385 * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated
386 * CURL_FORMADD_MEMORY if some allocation for string copying failed.
387 * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
389 ***************************************************************************/
392 CURLFORMcode FormAdd(struct curl_httppost **httppost,
393 struct curl_httppost **last_post,
396 FormInfo *first_form, *current_form, *form = NULL;
397 CURLFORMcode return_value = CURL_FORMADD_OK;
398 const char *prevtype = NULL;
399 struct curl_httppost *post = NULL;
400 CURLformoption option;
401 struct curl_forms *forms = NULL;
402 char *array_value=NULL; /* value read from an array */
404 /* This is a state variable, that if TRUE means that we're parsing an
405 array that we got passed to us. If FALSE we're parsing the input
406 va_list arguments. */
407 bool array_state = FALSE;
410 * We need to allocate the first struct to fill in.
412 first_form = (FormInfo *)calloc(sizeof(struct FormInfo), 1);
414 return CURL_FORMADD_MEMORY;
416 current_form = first_form;
419 * Loop through all the options set. Break if we have an error to report.
421 while (return_value == CURL_FORMADD_OK) {
423 /* first see if we have more parts of the array param */
425 /* get the upcoming option from the given array */
426 option = forms->option;
427 array_value = (char *)forms->value;
429 forms++; /* advance this to next entry */
430 if (CURLFORM_END == option) {
431 /* end of array state */
437 /* This is not array-state, get next option */
438 option = va_arg(params, CURLformoption);
439 if (CURLFORM_END == option)
446 /* we don't support an array from within an array */
447 return_value = CURL_FORMADD_ILLEGAL_ARRAY;
449 forms = va_arg(params, struct curl_forms *);
453 return_value = CURL_FORMADD_NULL;
458 * Set the Name property.
460 case CURLFORM_PTRNAME:
461 #ifdef CURL_DOES_CONVERSIONS
462 /* treat CURLFORM_PTR like CURLFORM_COPYNAME so we'll
463 have safe memory for the eventual conversion */
465 current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
467 case CURLFORM_COPYNAME:
468 if (current_form->name)
469 return_value = CURL_FORMADD_OPTION_TWICE;
471 char *name = array_state?
472 array_value:va_arg(params, char *);
474 current_form->name = name; /* store for the moment */
476 return_value = CURL_FORMADD_NULL;
479 case CURLFORM_NAMELENGTH:
480 if (current_form->namelength)
481 return_value = CURL_FORMADD_OPTION_TWICE;
483 current_form->namelength =
484 array_state?(size_t)array_value:(size_t)va_arg(params, long);
488 * Set the contents property.
490 case CURLFORM_PTRCONTENTS:
491 current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
492 case CURLFORM_COPYCONTENTS:
493 if (current_form->value)
494 return_value = CURL_FORMADD_OPTION_TWICE;
497 array_state?array_value:va_arg(params, char *);
499 current_form->value = value; /* store for the moment */
501 return_value = CURL_FORMADD_NULL;
504 case CURLFORM_CONTENTSLENGTH:
505 if (current_form->contentslength)
506 return_value = CURL_FORMADD_OPTION_TWICE;
508 current_form->contentslength =
509 array_state?(size_t)array_value:(size_t)va_arg(params, long);
512 /* Get contents from a given file name */
513 case CURLFORM_FILECONTENT:
514 if (current_form->flags != 0)
515 return_value = CURL_FORMADD_OPTION_TWICE;
517 const char *filename = array_state?
518 array_value:va_arg(params, char *);
520 current_form->value = strdup(filename);
521 if(!current_form->value)
522 return_value = CURL_FORMADD_MEMORY;
524 current_form->flags |= HTTPPOST_READFILE;
525 current_form->value_alloc = TRUE;
529 return_value = CURL_FORMADD_NULL;
533 /* We upload a file */
536 const char *filename = array_state?array_value:
537 va_arg(params, char *);
539 if (current_form->value) {
540 if (current_form->flags & HTTPPOST_FILENAME) {
542 if ((current_form = AddFormInfo(strdup(filename),
543 NULL, current_form)) == NULL)
544 return_value = CURL_FORMADD_MEMORY;
547 return_value = CURL_FORMADD_NULL;
550 return_value = CURL_FORMADD_OPTION_TWICE;
554 current_form->value = strdup(filename);
555 if(!current_form->value)
556 return_value = CURL_FORMADD_MEMORY;
558 current_form->flags |= HTTPPOST_FILENAME;
559 current_form->value_alloc = TRUE;
563 return_value = CURL_FORMADD_NULL;
568 case CURLFORM_BUFFER:
570 const char *filename = array_state?array_value:
571 va_arg(params, char *);
573 if (current_form->value) {
574 if (current_form->flags & HTTPPOST_BUFFER) {
576 if ((current_form = AddFormInfo(strdup(filename),
577 NULL, current_form)) == NULL)
578 return_value = CURL_FORMADD_MEMORY;
581 return_value = CURL_FORMADD_NULL;
584 return_value = CURL_FORMADD_OPTION_TWICE;
588 current_form->value = strdup(filename);
589 if(!current_form->value)
590 return_value = CURL_FORMADD_MEMORY;
593 return_value = CURL_FORMADD_NULL;
594 current_form->flags |= HTTPPOST_BUFFER;
599 case CURLFORM_BUFFERPTR:
600 current_form->flags |= HTTPPOST_PTRBUFFER;
601 if (current_form->buffer)
602 return_value = CURL_FORMADD_OPTION_TWICE;
605 array_state?array_value:va_arg(params, char *);
607 current_form->buffer = buffer; /* store for the moment */
609 return_value = CURL_FORMADD_NULL;
613 case CURLFORM_BUFFERLENGTH:
614 if (current_form->bufferlength)
615 return_value = CURL_FORMADD_OPTION_TWICE;
617 current_form->bufferlength =
618 array_state?(size_t)array_value:(size_t)va_arg(params, long);
621 case CURLFORM_CONTENTTYPE:
623 const char *contenttype =
624 array_state?array_value:va_arg(params, char *);
625 if (current_form->contenttype) {
626 if (current_form->flags & HTTPPOST_FILENAME) {
628 if ((current_form = AddFormInfo(NULL,
630 current_form)) == NULL)
631 return_value = CURL_FORMADD_MEMORY;
634 return_value = CURL_FORMADD_NULL;
637 return_value = CURL_FORMADD_OPTION_TWICE;
641 current_form->contenttype = strdup(contenttype);
642 if(!current_form->contenttype)
643 return_value = CURL_FORMADD_MEMORY;
645 current_form->contenttype_alloc = TRUE;
648 return_value = CURL_FORMADD_NULL;
652 case CURLFORM_CONTENTHEADER:
654 /* this "cast increases required alignment of target type" but
655 we consider it OK anyway */
656 struct curl_slist* list = array_state?
657 (struct curl_slist*)array_value:
658 va_arg(params, struct curl_slist*);
660 if( current_form->contentheader )
661 return_value = CURL_FORMADD_OPTION_TWICE;
663 current_form->contentheader = list;
667 case CURLFORM_FILENAME:
669 const char *filename = array_state?array_value:
670 va_arg(params, char *);
671 if( current_form->showfilename )
672 return_value = CURL_FORMADD_OPTION_TWICE;
674 current_form->showfilename = strdup(filename);
675 if(!current_form->showfilename)
676 return_value = CURL_FORMADD_MEMORY;
678 current_form->showfilename_alloc = TRUE;
683 return_value = CURL_FORMADD_UNKNOWN_OPTION;
687 if(CURL_FORMADD_OK == return_value) {
688 /* go through the list, check for copleteness and if everything is
689 * alright add the HttpPost item otherwise set return_value accordingly */
692 for(form = first_form;
695 if ( ((!form->name || !form->value) && !post) ||
696 ( (form->contentslength) &&
697 (form->flags & HTTPPOST_FILENAME) ) ||
698 ( (form->flags & HTTPPOST_FILENAME) &&
699 (form->flags & HTTPPOST_PTRCONTENTS) ) ||
702 (form->flags & HTTPPOST_BUFFER) &&
703 (form->flags & HTTPPOST_PTRBUFFER) ) ||
705 ( (form->flags & HTTPPOST_READFILE) &&
706 (form->flags & HTTPPOST_PTRCONTENTS) )
708 return_value = CURL_FORMADD_INCOMPLETE;
712 if ( ((form->flags & HTTPPOST_FILENAME) ||
713 (form->flags & HTTPPOST_BUFFER)) &&
714 !form->contenttype ) {
715 /* our contenttype is missing */
717 = strdup(ContentTypeForFilename(form->value, prevtype));
718 if(!form->contenttype) {
719 return_value = CURL_FORMADD_MEMORY;
722 form->contenttype_alloc = TRUE;
724 if ( !(form->flags & HTTPPOST_PTRNAME) &&
725 (form == first_form) ) {
726 /* copy name (without strdup; possibly contains null characters) */
727 form->name = memdup(form->name, form->namelength);
729 return_value = CURL_FORMADD_MEMORY;
732 form->name_alloc = TRUE;
734 if ( !(form->flags & HTTPPOST_FILENAME) &&
735 !(form->flags & HTTPPOST_READFILE) &&
736 !(form->flags & HTTPPOST_PTRCONTENTS) &&
737 !(form->flags & HTTPPOST_PTRBUFFER) ) {
738 /* copy value (without strdup; possibly contains null characters) */
739 form->value = memdup(form->value, form->contentslength);
741 return_value = CURL_FORMADD_MEMORY;
744 form->value_alloc = TRUE;
746 post = AddHttpPost(form->name, form->namelength,
747 form->value, form->contentslength,
748 form->buffer, form->bufferlength,
749 form->contenttype, form->flags,
750 form->contentheader, form->showfilename,
755 return_value = CURL_FORMADD_MEMORY;
759 if (form->contenttype)
760 prevtype = form->contenttype;
766 /* we return on error, free possibly allocated fields */
772 if(form->value_alloc)
774 if(form->contenttype_alloc)
775 free(form->contenttype);
776 if(form->showfilename_alloc)
777 free(form->showfilename);
781 /* always delete the allocated memory before returning */
783 while (form != NULL) {
784 FormInfo *delete_form;
795 * curl_formadd() is a public API to add a section to the multipart formpost.
798 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
799 struct curl_httppost **last_post,
804 va_start(arg, last_post);
805 result = FormAdd(httppost, last_post, arg);
811 * AddFormData() adds a chunk of data to the FormData linked list.
813 * size is incremented by the chunk length, unless it is NULL
815 static CURLcode AddFormData(struct FormData **formp,
821 struct FormData *newform = (struct FormData *)
822 malloc(sizeof(struct FormData));
824 return CURLE_OUT_OF_MEMORY;
825 newform->next = NULL;
827 /* we make it easier for plain strings: */
829 length = strlen((char *)line);
831 newform->line = (char *)malloc(length+1);
832 if (!newform->line) {
834 return CURLE_OUT_OF_MEMORY;
836 memcpy(newform->line, line, length);
837 newform->length = length;
838 newform->line[length]=0; /* zero terminate for easier debugging */
839 newform->type = type;
842 (*formp)->next = newform;
849 if((type == FORM_DATA) || (type == FORM_CONTENT))
852 /* Since this is a file to be uploaded here, add the size of the actual
854 if(!strequal("-", newform->line)) {
856 if(!stat(newform->line, &file)) {
857 *size += file.st_size;
866 * AddFormDataf() adds printf()-style formatted data to the formdata chain.
869 static CURLcode AddFormDataf(struct FormData **formp,
871 const char *fmt, ...)
876 vsnprintf(s, sizeof(s), fmt, ap);
879 return AddFormData(formp, FORM_DATA, s, 0, size);
883 * Curl_formclean() is used from http.c, this cleans a built FormData linked
886 void Curl_formclean(struct FormData **form_ptr)
888 struct FormData *next, *form;
895 next=form->next; /* the following form line */
896 free(form->line); /* free the line */
897 free(form); /* free the struct */
899 } while ((form = next) != NULL); /* continue */
904 #ifdef CURL_DOES_CONVERSIONS
906 * Curl_formcovert() is used from http.c, this converts any
907 form items that need to be sent in the network encoding.
908 Returns CURLE_OK on success.
910 CURLcode Curl_formconvert(struct SessionHandle *data, struct FormData *form)
912 struct FormData *next;
919 return CURLE_BAD_FUNCTION_ARGUMENT;
922 next=form->next; /* the following form line */
923 if (form->type == FORM_DATA) {
924 rc = Curl_convert_to_network(data, form->line, form->length);
925 /* Curl_convert_to_network calls failf if unsuccessful */
929 } while ((form = next) != NULL); /* continue */
932 #endif /* CURL_DOES_CONVERSIONS */
936 * Serialize a curl_httppost struct.
937 * Returns 0 on success.
939 int curl_formget(struct curl_httppost *form, void *arg,
940 curl_formget_callback append)
944 struct FormData *data, *ptr;
946 rc = Curl_getFormData(&data, form, NULL, &size);
950 for (ptr = data; ptr; ptr = ptr->next) {
951 if (ptr->type == FORM_FILE) {
956 Curl_FormInit(&temp, ptr);
959 nread = readfromfile(&temp, buffer, sizeof(buffer));
960 if ((nread == (size_t) -1) || (nread != append(arg, buffer, nread))) {
964 Curl_formclean(&data);
967 } while (nread == sizeof(buffer));
969 if (ptr->length != append(arg, ptr->line, ptr->length)) {
970 Curl_formclean(&data);
975 Curl_formclean(&data);
980 * curl_formfree() is an external function to free up a whole form post
983 void curl_formfree(struct curl_httppost *form)
985 struct curl_httppost *next;
988 /* no form to free, just get out of this */
992 next=form->next; /* the following form line */
994 /* recurse to sub-contents */
996 curl_formfree(form->more);
998 if( !(form->flags & HTTPPOST_PTRNAME) && form->name)
999 free(form->name); /* free the name */
1000 if( !(form->flags & HTTPPOST_PTRCONTENTS) && form->contents)
1001 free(form->contents); /* free the contents */
1002 if(form->contenttype)
1003 free(form->contenttype); /* free the content type */
1004 if(form->showfilename)
1005 free(form->showfilename); /* free the faked file name */
1006 free(form); /* free the struct */
1008 } while ((form = next) != NULL); /* continue */
1011 #ifndef HAVE_BASENAME
1013 (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
1016 The basename() function shall take the pathname pointed to by path and
1017 return a pointer to the final component of the pathname, deleting any
1018 trailing '/' characters.
1020 If the string pointed to by path consists entirely of the '/' character,
1021 basename() shall return a pointer to the string "/". If the string pointed
1022 to by path is exactly "//", it is implementation-defined whether '/' or "//"
1025 If path is a null pointer or points to an empty string, basename() shall
1026 return a pointer to the string ".".
1028 The basename() function may modify the string pointed to by path, and may
1029 return a pointer to static storage that may then be overwritten by a
1030 subsequent call to basename().
1032 The basename() function need not be reentrant. A function that is not
1033 required to be reentrant is not required to be thread-safe.
1036 static char *basename(char *path)
1038 /* Ignore all the details above for now and make a quick and simple
1039 implementaion here */
1043 s1=strrchr(path, '/');
1044 s2=strrchr(path, '\\');
1047 path = (s1 > s2? s1 : s2)+1;
1058 static char *strippath(const char *fullfile)
1062 filename = strdup(fullfile); /* duplicate since basename() may ruin the
1063 buffer it works on */
1066 base = strdup(basename(filename));
1068 free(filename); /* free temporary buffer */
1070 return base; /* returns an allocated string! */
1074 * Curl_getFormData() converts a linked list of "meta data" into a complete
1075 * (possibly huge) multipart formdata. The input list is in 'post', while the
1076 * output resulting linked lists gets stored in '*finalform'. *sizep will get
1077 * the total size of the whole POST.
1078 * A multipart/form_data content-type is built, unless a custom content-type
1079 * is passed in 'custom_content_type'.
1082 CURLcode Curl_getFormData(struct FormData **finalform,
1083 struct curl_httppost *post,
1084 const char *custom_content_type,
1087 struct FormData *form = NULL;
1088 struct FormData *firstform;
1089 struct curl_httppost *file;
1090 CURLcode result = CURLE_OK;
1092 curl_off_t size=0; /* support potentially ENORMOUS formposts */
1094 char *fileboundary=NULL;
1095 struct curl_slist* curList;
1097 *finalform=NULL; /* default form is empty */
1100 return result; /* no input => no output! */
1102 boundary = Curl_FormBoundary();
1104 return CURLE_OUT_OF_MEMORY;
1106 /* Make the first line of the output */
1107 result = AddFormDataf(&form, NULL,
1108 "%s; boundary=%s\r\n",
1109 custom_content_type?custom_content_type:
1110 "Content-Type: multipart/form-data",
1117 /* we DO NOT include that line in the total size of the POST, since it'll be
1118 part of the header! */
1125 result = AddFormDataf(&form, &size, "\r\n");
1131 result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
1135 /* Maybe later this should be disabled when a custom_content_type is
1136 passed, since Content-Disposition is not meaningful for all multipart
1139 result = AddFormDataf(&form, &size,
1140 "Content-Disposition: form-data; name=\"");
1144 result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
1149 result = AddFormDataf(&form, &size, "\"");
1154 /* If used, this is a link to more file names, we must then do
1155 the magic to include several files with the same field name */
1157 fileboundary = Curl_FormBoundary();
1159 result = AddFormDataf(&form, &size,
1160 "\r\nContent-Type: multipart/mixed,"
1171 /* If 'showfilename' is set, that is a faked name passed on to us
1172 to use to in the formpost. If that is not set, the actually used
1173 local file name should be added. */
1176 /* if multiple-file */
1178 (!file->showfilename)?strippath(file->contents):NULL;
1180 result = AddFormDataf(&form, &size,
1181 "\r\n--%s\r\nContent-Disposition: "
1182 "attachment; filename=\"%s\"",
1184 (file->showfilename?file->showfilename:
1191 else if((post->flags & HTTPPOST_FILENAME) ||
1192 (post->flags & HTTPPOST_BUFFER)) {
1195 (!post->showfilename)?strippath(post->contents):NULL;
1197 result = AddFormDataf(&form, &size,
1198 "; filename=\"%s\"",
1199 (post->showfilename?post->showfilename:
1208 if(file->contenttype) {
1209 /* we have a specified type */
1210 result = AddFormDataf(&form, &size,
1211 "\r\nContent-Type: %s",
1217 curList = file->contentheader;
1219 /* Process the additional headers specified for this form */
1220 result = AddFormDataf( &form, &size, "\r\n%s", curList->data );
1223 curList = curList->next;
1226 Curl_formclean(&firstform);
1232 /* The header Content-Transfer-Encoding: seems to confuse some receivers
1233 * (like the built-in PHP engine). While I can't see any reason why it
1234 * should, I can just as well skip this to the benefit of the users who
1235 * are using such confused receivers.
1238 if(file->contenttype &&
1239 !checkprefix("text/", file->contenttype)) {
1240 /* this is not a text content, mention our binary encoding */
1241 result = AddFormDataf(&form, &size,
1242 "\r\nContent-Transfer-Encoding: binary");
1248 result = AddFormDataf(&form, &size, "\r\n\r\n");
1252 if((post->flags & HTTPPOST_FILENAME) ||
1253 (post->flags & HTTPPOST_READFILE)) {
1254 /* we should include the contents from the specified file */
1257 fileread = strequal("-", file->contents)?
1258 stdin:fopen(file->contents, "rb"); /* binary read for win32 */
1261 * VMS: This only allows for stream files on VMS. Stream files are
1262 * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
1263 * every record needs to have a \n appended & 1 added to SIZE
1267 if(fileread != stdin) {
1268 /* close the file again */
1270 /* add the file name only - for later reading from this */
1271 result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
1274 /* When uploading from stdin, we can't know the size of the file,
1275 * thus must read the full file as before. We *could* use chunked
1276 * transfer-encoding, but that only works for HTTP 1.1 and we
1277 * can't be sure we work with such a server.
1281 while ((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) {
1282 result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
1289 Curl_formclean(&firstform);
1298 "\n==> Curl_getFormData couldn't open/read \"%s\"\n",
1301 Curl_formclean(&firstform);
1304 return CURLE_READ_ERROR;
1308 else if (post->flags & HTTPPOST_BUFFER) {
1309 /* include contents of buffer */
1310 result = AddFormData(&form, FORM_CONTENT, post->buffer,
1311 post->bufferlength, &size);
1317 /* include the contents we got */
1318 result = AddFormData(&form, FORM_CONTENT, post->contents,
1319 post->contentslength, &size);
1323 } while ((file = file->more) != NULL); /* for each specified file for this field */
1325 Curl_formclean(&firstform);
1331 /* this was a multiple-file inclusion, make a termination file
1333 result = AddFormDataf(&form, &size,
1341 } while ((post = post->next) != NULL); /* for each field */
1343 Curl_formclean(&firstform);
1348 /* end-boundary for everything */
1349 result = AddFormDataf(&form, &size,
1353 Curl_formclean(&firstform);
1362 *finalform=firstform;
1368 * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
1369 * and resets the 'sent' counter.
1371 int Curl_FormInit(struct Form *form, struct FormData *formdata )
1374 return 1; /* error */
1376 form->data = formdata;
1383 static size_t readfromfile(struct Form *form, char *buffer, size_t size)
1387 /* this file hasn't yet been opened */
1388 form->fp = fopen(form->data->line, "rb"); /* b is for binary */
1390 return (size_t)-1; /* failure */
1392 nread = fread(buffer, 1, size, form->fp);
1395 /* this is the last chunk from the file, move on */
1398 form->data = form->data->next;
1405 * Curl_FormReader() is the fread() emulation function that will be used to
1406 * deliver the formdata to the transfer loop and then sent away to the peer.
1408 size_t Curl_FormReader(char *buffer,
1417 form=(struct Form *)mydata;
1419 wantedsize = size * nitems;
1422 return 0; /* nothing, error, empty */
1424 if(form->data->type == FORM_FILE) {
1425 gotsize = readfromfile(form, buffer, wantedsize);
1428 /* If positive or -1, return. If zero, continue! */
1433 if( (form->data->length - form->sent ) > wantedsize - gotsize) {
1435 memcpy(buffer + gotsize , form->data->line + form->sent,
1436 wantedsize - gotsize);
1438 form->sent += wantedsize-gotsize;
1443 memcpy(buffer+gotsize,
1444 form->data->line + form->sent,
1445 (form->data->length - form->sent) );
1446 gotsize += form->data->length - form->sent;
1450 form->data = form->data->next; /* advance */
1452 } while(form->data && (form->data->type != FORM_FILE));
1453 /* If we got an empty line and we have more data, we proceed to the next
1454 line immediately to avoid returning zero before we've reached the end.
1455 This is the bug reported November 22 1999 on curl 6.3. (Daniel) */
1461 * Curl_formpostheader() returns the first line of the formpost, the
1462 * request-header part (which is not part of the request-body like the rest of
1465 char *Curl_formpostheader(void *formp, size_t *len)
1468 struct Form *form=(struct Form *)formp;
1471 return 0; /* nothing, ERROR! */
1473 header = form->data->line;
1474 *len = form->data->length;
1476 form->data = form->data->next; /* advance */
1483 int FormAddTest(const char * errormsg,
1484 struct curl_httppost **httppost,
1485 struct curl_httppost **last_post,
1490 va_start(arg, last_post);
1491 if ((result = FormAdd(httppost, last_post, arg)))
1492 fprintf (stderr, "ERROR doing FormAdd ret: %d action: %s\n", result,
1499 int main(int argc, argv_item_t argv[])
1501 char name1[] = "simple_COPYCONTENTS";
1502 char name2[] = "COPYCONTENTS_+_CONTENTTYPE";
1503 char name3[] = "PTRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH";
1504 char name4[] = "simple_PTRCONTENTS";
1505 char name5[] = "PTRCONTENTS_+_CONTENTSLENGTH";
1506 char name6[] = "PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE";
1507 char name7[] = "FILE1_+_CONTENTTYPE";
1508 char name8[] = "FILE1_+_FILE2";
1509 char name9[] = "FILE1_+_FILE2_+_FILE3";
1510 char name10[] = "ARRAY: FILE1_+_FILE2_+_FILE3";
1511 char name11[] = "FILECONTENT";
1512 char value1[] = "value for simple COPYCONTENTS";
1513 char value2[] = "value for COPYCONTENTS + CONTENTTYPE";
1514 char value3[] = "value for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH";
1515 char value4[] = "value for simple PTRCONTENTS";
1516 char value5[] = "value for PTRCONTENTS + CONTENTSLENGTH";
1517 char value6[] = "value for PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE";
1518 char value7[] = "inet_ntoa_r.h";
1519 char value8[] = "Makefile.b32";
1520 char type2[] = "image/gif";
1521 char type6[] = "text/plain";
1522 char type7[] = "text/html";
1523 int name3length = strlen(name3);
1524 int value3length = strlen(value3);
1525 int value5length = strlen(value5);
1526 int value6length = strlen(value6);
1532 struct curl_httppost *httppost=NULL;
1533 struct curl_httppost *last_post=NULL;
1534 struct curl_forms forms[4];
1536 struct FormData *form;
1537 struct Form formread;
1542 if (FormAddTest("simple COPYCONTENTS test", &httppost, &last_post,
1543 CURLFORM_COPYNAME, name1, CURLFORM_COPYCONTENTS, value1,
1546 if (FormAddTest("COPYCONTENTS + CONTENTTYPE test", &httppost, &last_post,
1547 CURLFORM_COPYNAME, name2, CURLFORM_COPYCONTENTS, value2,
1548 CURLFORM_CONTENTTYPE, type2, CURLFORM_END))
1550 /* make null character at start to check that contentslength works
1554 if (FormAddTest("PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH test",
1555 &httppost, &last_post,
1556 CURLFORM_PTRNAME, name3, CURLFORM_COPYCONTENTS, value3,
1557 CURLFORM_CONTENTSLENGTH, value3length,
1558 CURLFORM_NAMELENGTH, name3length, CURLFORM_END))
1560 if (FormAddTest("simple PTRCONTENTS test", &httppost, &last_post,
1561 CURLFORM_COPYNAME, name4, CURLFORM_PTRCONTENTS, value4,
1564 /* make null character at start to check that contentslength works
1567 if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH test", &httppost, &last_post,
1568 CURLFORM_COPYNAME, name5, CURLFORM_PTRCONTENTS, value5,
1569 CURLFORM_CONTENTSLENGTH, value5length, CURLFORM_END))
1571 /* make null character at start to check that contentslength works
1574 if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE test",
1575 &httppost, &last_post,
1576 CURLFORM_COPYNAME, name6, CURLFORM_PTRCONTENTS, value6,
1577 CURLFORM_CONTENTSLENGTH, value6length,
1578 CURLFORM_CONTENTTYPE, type6, CURLFORM_END))
1580 if (FormAddTest("FILE + CONTENTTYPE test", &httppost, &last_post,
1581 CURLFORM_COPYNAME, name7, CURLFORM_FILE, value7,
1582 CURLFORM_CONTENTTYPE, type7, CURLFORM_END))
1584 if (FormAddTest("FILE1 + FILE2 test", &httppost, &last_post,
1585 CURLFORM_COPYNAME, name8, CURLFORM_FILE, value7,
1586 CURLFORM_FILE, value8, CURLFORM_END))
1588 if (FormAddTest("FILE1 + FILE2 + FILE3 test", &httppost, &last_post,
1589 CURLFORM_COPYNAME, name9, CURLFORM_FILE, value7,
1590 CURLFORM_FILE, value8, CURLFORM_FILE, value7, CURLFORM_END))
1592 forms[0].option = CURLFORM_FILE;
1593 forms[0].value = value7;
1594 forms[1].option = CURLFORM_FILE;
1595 forms[1].value = value8;
1596 forms[2].option = CURLFORM_FILE;
1597 forms[2].value = value7;
1598 forms[3].option = CURLFORM_END;
1599 if (FormAddTest("FILE1 + FILE2 + FILE3 ARRAY test", &httppost, &last_post,
1600 CURLFORM_COPYNAME, name10, CURLFORM_ARRAY, forms,
1603 if (FormAddTest("FILECONTENT test", &httppost, &last_post,
1604 CURLFORM_COPYNAME, name11, CURLFORM_FILECONTENT, value7,
1608 rc = Curl_getFormData(&form, httppost, NULL, &size);
1609 if(rc != CURLE_OK) {
1610 if(rc != CURLE_READ_ERROR) {
1611 const char *errortext = curl_easy_strerror(rc);
1612 fprintf(stdout, "\n==> Curl_getFormData error: %s\n", errortext);
1617 Curl_FormInit(&formread, form);
1620 nread = Curl_FormReader(buffer, 1, sizeof(buffer),
1625 fwrite(buffer, nread, 1, stdout);
1628 fprintf(stdout, "size: ");
1629 fprintf(stdout, CURL_FORMAT_OFF_T, size);
1630 fprintf(stdout, "\n");
1632 fprintf(stdout, "\n==> %d Test(s) failed!\n", errors);
1634 fprintf(stdout, "\nAll Tests seem to have worked (please check output)\n");
1639 #endif /* _FORM_DEBUG */
1641 #else /* CURL_DISABLE_HTTP */
1642 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
1643 struct curl_httppost **last_post,
1648 return CURL_FORMADD_DISABLED;
1651 int curl_formget(struct curl_httppost *form, void *arg,
1652 curl_formget_callback append)
1657 return CURL_FORMADD_DISABLED;
1660 void curl_formfree(struct curl_httppost *form)
1663 /* does nothing HTTP is disabled */
1666 #endif /* CURL_DISABLE_HTTP */
1668 #if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
1671 * Curl_FormBoundary() creates a suitable boundary string and returns an
1672 * allocated one. This is also used by SSL-code so it must be present even
1673 * if HTTP is disabled!
1675 char *Curl_FormBoundary(void)
1678 static int randomizer; /* this is just so that two boundaries within
1679 the same form won't be identical */
1682 static const char table16[]="abcdef0123456789";
1684 retstring = (char *)malloc(BOUNDARY_LENGTH+1);
1687 return NULL; /* failed */
1689 srand((unsigned int)time(NULL)+randomizer++); /* seed */
1691 strcpy(retstring, "----------------------------");
1693 for(i=strlen(retstring); i<BOUNDARY_LENGTH; i++)
1694 retstring[i] = table16[rand()%16];
1696 /* 28 dashes and 12 hexadecimal digits makes 12^16 (184884258895036416)
1698 retstring[BOUNDARY_LENGTH]=0; /* zero terminate */
1703 #endif /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */