1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2008, 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.
21 * $Id: formdata.c,v 1.1.1.1 2008-09-23 16:32:05 hoffman Exp $
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
,
168 char *showfilename
, char *userp
,
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
;
192 /* now, point our 'more' to the original 'more' */
193 post
->more
= parent_post
->more
;
195 /* then move the original 'more' to point to ourselves */
196 parent_post
->more
= post
;
199 /* make the previous point to this */
201 (*last_post
)->next
= post
;
210 /***************************************************************************
214 * Adds a FormInfo structure to the list presented by parent_form_info.
216 * Returns newly allocated FormInfo on success and NULL if malloc failed/
217 * parent_form_info is NULL.
219 ***************************************************************************/
220 static FormInfo
* AddFormInfo(char *value
,
222 FormInfo
*parent_form_info
)
225 form_info
= (FormInfo
*)malloc(sizeof(FormInfo
));
227 memset(form_info
, 0, sizeof(FormInfo
));
229 form_info
->value
= value
;
231 form_info
->contenttype
= contenttype
;
232 form_info
->flags
= HTTPPOST_FILENAME
;
237 if(parent_form_info
) {
238 /* now, point our 'more' to the original 'more' */
239 form_info
->more
= parent_form_info
->more
;
241 /* then move the original 'more' to point to ourselves */
242 parent_form_info
->more
= form_info
;
250 /***************************************************************************
252 * ContentTypeForFilename()
254 * Provides content type for filename if one of the known types (else
255 * (either the prevtype or the default is returned).
257 * Returns some valid contenttype for filename.
259 ***************************************************************************/
260 static const char * ContentTypeForFilename (const char *filename
,
261 const char *prevtype
)
263 const char *contenttype
= NULL
;
266 * No type was specified, we scan through a few well-known
267 * extensions and pick the first we match!
270 const char *extension
;
273 static const struct ContentType ctts
[]={
274 {".gif", "image/gif"},
275 {".jpg", "image/jpeg"},
276 {".jpeg", "image/jpeg"},
277 {".txt", "text/plain"},
278 {".html", "text/html"}
282 /* default to the previously set/used! */
283 contenttype
= prevtype
;
285 contenttype
= HTTPPOST_CONTENTTYPE_DEFAULT
;
287 if(filename
) { /* in case a NULL was passed in */
288 for(i
=0; i
<sizeof(ctts
)/sizeof(ctts
[0]); i
++) {
289 if(strlen(filename
) >= strlen(ctts
[i
].extension
)) {
290 if(strequal(filename
+
291 strlen(filename
) - strlen(ctts
[i
].extension
),
292 ctts
[i
].extension
)) {
293 contenttype
= ctts
[i
].type
;
299 /* we have a contenttype by now */
303 /***************************************************************************
307 * Copies the 'source' data to a newly allocated buffer buffer (that is
308 * returned). Uses buffer_length if not null, else uses strlen to determine
309 * the length of the buffer to be copied
311 * Returns the new pointer or NULL on failure.
313 ***************************************************************************/
314 static char *memdup(const char *src
, size_t buffer_length
)
321 length
= buffer_length
;
323 length
= strlen(src
);
327 /* no length and a NULL src pointer! */
328 return strdup((char *)"");
330 buffer
= (char*)malloc(length
+add
);
332 return NULL
; /* fail */
334 memcpy(buffer
, src
, length
);
336 /* if length unknown do null termination */
338 buffer
[length
] = '\0';
343 /***************************************************************************
347 * Stores a formpost parameter and builds the appropriate linked list.
349 * Has two principal functionalities: using files and byte arrays as
350 * post parts. Byte arrays are either copied or just the pointer is stored
351 * (as the user requests) while for files only the filename and not the
354 * While you may have only one byte array for each name, multiple filenames
355 * are allowed (and because of this feature CURLFORM_END is needed after
356 * using CURLFORM_FILE).
360 * Simple name/value pair with copied contents:
361 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
362 * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
364 * name/value pair where only the content pointer is remembered:
365 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
366 * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
367 * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
369 * storing a filename (CONTENTTYPE is optional!):
370 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
371 * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
374 * storing multiple filenames:
375 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
376 * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
379 * CURL_FORMADD_OK on success
380 * CURL_FORMADD_MEMORY if the FormInfo allocation fails
381 * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
382 * CURL_FORMADD_NULL if a null pointer was given for a char
383 * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
384 * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
385 * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or an error)
386 * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated
387 * CURL_FORMADD_MEMORY if some allocation for string copying failed.
388 * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
390 ***************************************************************************/
393 CURLFORMcode
FormAdd(struct curl_httppost
**httppost
,
394 struct curl_httppost
**last_post
,
397 FormInfo
*first_form
, *current_form
, *form
= NULL
;
398 CURLFORMcode return_value
= CURL_FORMADD_OK
;
399 const char *prevtype
= NULL
;
400 struct curl_httppost
*post
= NULL
;
401 CURLformoption option
;
402 struct curl_forms
*forms
= NULL
;
403 char *array_value
=NULL
; /* value read from an array */
405 /* This is a state variable, that if TRUE means that we're parsing an
406 array that we got passed to us. If FALSE we're parsing the input
407 va_list arguments. */
408 bool array_state
= FALSE
;
411 * We need to allocate the first struct to fill in.
413 first_form
= (FormInfo
*)calloc(sizeof(struct FormInfo
), 1);
415 return CURL_FORMADD_MEMORY
;
417 current_form
= first_form
;
420 * Loop through all the options set. Break if we have an error to report.
422 while(return_value
== CURL_FORMADD_OK
) {
424 /* first see if we have more parts of the array param */
426 /* get the upcoming option from the given array */
427 option
= forms
->option
;
428 array_value
= (char *)forms
->value
;
430 forms
++; /* advance this to next entry */
431 if(CURLFORM_END
== option
) {
432 /* end of array state */
438 /* This is not array-state, get next option */
439 option
= va_arg(params
, CURLformoption
);
440 if(CURLFORM_END
== option
)
447 /* we don't support an array from within an array */
448 return_value
= CURL_FORMADD_ILLEGAL_ARRAY
;
450 forms
= va_arg(params
, struct curl_forms
*);
454 return_value
= CURL_FORMADD_NULL
;
459 * Set the Name property.
461 case CURLFORM_PTRNAME
:
462 #ifdef CURL_DOES_CONVERSIONS
463 /* treat CURLFORM_PTR like CURLFORM_COPYNAME so we'll
464 have safe memory for the eventual conversion */
466 current_form
->flags
|= HTTPPOST_PTRNAME
; /* fall through */
468 case CURLFORM_COPYNAME
:
469 if(current_form
->name
)
470 return_value
= CURL_FORMADD_OPTION_TWICE
;
472 char *name
= array_state
?
473 array_value
:va_arg(params
, char *);
475 current_form
->name
= name
; /* store for the moment */
477 return_value
= CURL_FORMADD_NULL
;
480 case CURLFORM_NAMELENGTH
:
481 if(current_form
->namelength
)
482 return_value
= CURL_FORMADD_OPTION_TWICE
;
484 current_form
->namelength
=
485 array_state
?(size_t)array_value
:(size_t)va_arg(params
, long);
489 * Set the contents property.
491 case CURLFORM_PTRCONTENTS
:
492 current_form
->flags
|= HTTPPOST_PTRCONTENTS
; /* fall through */
493 case CURLFORM_COPYCONTENTS
:
494 if(current_form
->value
)
495 return_value
= CURL_FORMADD_OPTION_TWICE
;
498 array_state
?array_value
:va_arg(params
, char *);
500 current_form
->value
= value
; /* store for the moment */
502 return_value
= CURL_FORMADD_NULL
;
505 case CURLFORM_CONTENTSLENGTH
:
506 if(current_form
->contentslength
)
507 return_value
= CURL_FORMADD_OPTION_TWICE
;
509 current_form
->contentslength
=
510 array_state
?(size_t)array_value
:(size_t)va_arg(params
, long);
513 /* Get contents from a given file name */
514 case CURLFORM_FILECONTENT
:
515 if(current_form
->flags
!= 0)
516 return_value
= CURL_FORMADD_OPTION_TWICE
;
518 const char *filename
= array_state
?
519 array_value
:va_arg(params
, char *);
521 current_form
->value
= strdup(filename
);
522 if(!current_form
->value
)
523 return_value
= CURL_FORMADD_MEMORY
;
525 current_form
->flags
|= HTTPPOST_READFILE
;
526 current_form
->value_alloc
= TRUE
;
530 return_value
= CURL_FORMADD_NULL
;
534 /* We upload a file */
537 const char *filename
= array_state
?array_value
:
538 va_arg(params
, char *);
540 if(current_form
->value
) {
541 if(current_form
->flags
& HTTPPOST_FILENAME
) {
543 if((current_form
= AddFormInfo(strdup(filename
),
544 NULL
, current_form
)) == NULL
)
545 return_value
= CURL_FORMADD_MEMORY
;
548 return_value
= CURL_FORMADD_NULL
;
551 return_value
= CURL_FORMADD_OPTION_TWICE
;
555 current_form
->value
= strdup(filename
);
556 if(!current_form
->value
)
557 return_value
= CURL_FORMADD_MEMORY
;
559 current_form
->flags
|= HTTPPOST_FILENAME
;
560 current_form
->value_alloc
= TRUE
;
564 return_value
= CURL_FORMADD_NULL
;
569 case CURLFORM_BUFFER
:
571 const char *filename
= array_state
?array_value
:
572 va_arg(params
, char *);
574 if(current_form
->value
) {
575 if(current_form
->flags
& HTTPPOST_BUFFER
) {
577 if((current_form
= AddFormInfo(strdup(filename
),
578 NULL
, current_form
)) == NULL
)
579 return_value
= CURL_FORMADD_MEMORY
;
582 return_value
= CURL_FORMADD_NULL
;
585 return_value
= CURL_FORMADD_OPTION_TWICE
;
589 current_form
->value
= strdup(filename
);
590 if(!current_form
->value
)
591 return_value
= CURL_FORMADD_MEMORY
;
594 return_value
= CURL_FORMADD_NULL
;
595 current_form
->flags
|= HTTPPOST_BUFFER
;
600 case CURLFORM_BUFFERPTR
:
601 current_form
->flags
|= HTTPPOST_PTRBUFFER
;
602 if(current_form
->buffer
)
603 return_value
= CURL_FORMADD_OPTION_TWICE
;
606 array_state
?array_value
:va_arg(params
, char *);
608 current_form
->buffer
= buffer
; /* store for the moment */
610 return_value
= CURL_FORMADD_NULL
;
614 case CURLFORM_BUFFERLENGTH
:
615 if(current_form
->bufferlength
)
616 return_value
= CURL_FORMADD_OPTION_TWICE
;
618 current_form
->bufferlength
=
619 array_state
?(size_t)array_value
:(size_t)va_arg(params
, long);
622 case CURLFORM_STREAM
:
623 current_form
->flags
|= HTTPPOST_CALLBACK
;
624 if(current_form
->userp
)
625 return_value
= CURL_FORMADD_OPTION_TWICE
;
628 array_state
?array_value
:va_arg(params
, char *);
630 current_form
->userp
= userp
;
631 current_form
->value
= userp
; /* this isn't strictly true but we
632 derive a value from this later on
633 and we need this non-NULL to be
634 accepted as a fine form part */
637 return_value
= CURL_FORMADD_NULL
;
641 case CURLFORM_CONTENTTYPE
:
643 const char *contenttype
=
644 array_state
?array_value
:va_arg(params
, char *);
645 if(current_form
->contenttype
) {
646 if(current_form
->flags
& HTTPPOST_FILENAME
) {
648 if((current_form
= AddFormInfo(NULL
,
650 current_form
)) == NULL
)
651 return_value
= CURL_FORMADD_MEMORY
;
654 return_value
= CURL_FORMADD_NULL
;
657 return_value
= CURL_FORMADD_OPTION_TWICE
;
661 current_form
->contenttype
= strdup(contenttype
);
662 if(!current_form
->contenttype
)
663 return_value
= CURL_FORMADD_MEMORY
;
665 current_form
->contenttype_alloc
= TRUE
;
668 return_value
= CURL_FORMADD_NULL
;
672 case CURLFORM_CONTENTHEADER
:
674 /* this "cast increases required alignment of target type" but
675 we consider it OK anyway */
676 struct curl_slist
* list
= array_state
?
677 (struct curl_slist
*)array_value
:
678 va_arg(params
, struct curl_slist
*);
680 if( current_form
->contentheader
)
681 return_value
= CURL_FORMADD_OPTION_TWICE
;
683 current_form
->contentheader
= list
;
687 case CURLFORM_FILENAME
:
689 const char *filename
= array_state
?array_value
:
690 va_arg(params
, char *);
691 if( current_form
->showfilename
)
692 return_value
= CURL_FORMADD_OPTION_TWICE
;
694 current_form
->showfilename
= strdup(filename
);
695 if(!current_form
->showfilename
)
696 return_value
= CURL_FORMADD_MEMORY
;
698 current_form
->showfilename_alloc
= TRUE
;
703 return_value
= CURL_FORMADD_UNKNOWN_OPTION
;
707 if(CURL_FORMADD_OK
== return_value
) {
708 /* go through the list, check for completeness and if everything is
709 * alright add the HttpPost item otherwise set return_value accordingly */
712 for(form
= first_form
;
715 if( ((!form
->name
|| !form
->value
) && !post
) ||
716 ( (form
->contentslength
) &&
717 (form
->flags
& HTTPPOST_FILENAME
) ) ||
718 ( (form
->flags
& HTTPPOST_FILENAME
) &&
719 (form
->flags
& HTTPPOST_PTRCONTENTS
) ) ||
722 (form
->flags
& HTTPPOST_BUFFER
) &&
723 (form
->flags
& HTTPPOST_PTRBUFFER
) ) ||
725 ( (form
->flags
& HTTPPOST_READFILE
) &&
726 (form
->flags
& HTTPPOST_PTRCONTENTS
) )
728 return_value
= CURL_FORMADD_INCOMPLETE
;
732 if( ((form
->flags
& HTTPPOST_FILENAME
) ||
733 (form
->flags
& HTTPPOST_BUFFER
)) &&
734 !form
->contenttype
) {
735 /* our contenttype is missing */
737 = strdup(ContentTypeForFilename(form
->value
, prevtype
));
738 if(!form
->contenttype
) {
739 return_value
= CURL_FORMADD_MEMORY
;
742 form
->contenttype_alloc
= TRUE
;
744 if( !(form
->flags
& HTTPPOST_PTRNAME
) &&
745 (form
== first_form
) ) {
746 /* copy name (without strdup; possibly contains null characters) */
747 form
->name
= memdup(form
->name
, form
->namelength
);
749 return_value
= CURL_FORMADD_MEMORY
;
752 form
->name_alloc
= TRUE
;
754 if( !(form
->flags
& (HTTPPOST_FILENAME
| HTTPPOST_READFILE
|
755 HTTPPOST_PTRCONTENTS
| HTTPPOST_PTRBUFFER
|
756 HTTPPOST_CALLBACK
)) ) {
757 /* copy value (without strdup; possibly contains null characters) */
758 form
->value
= memdup(form
->value
, form
->contentslength
);
760 return_value
= CURL_FORMADD_MEMORY
;
763 form
->value_alloc
= TRUE
;
765 post
= AddHttpPost(form
->name
, form
->namelength
,
766 form
->value
, form
->contentslength
,
767 form
->buffer
, form
->bufferlength
,
768 form
->contenttype
, form
->flags
,
769 form
->contentheader
, form
->showfilename
,
775 return_value
= CURL_FORMADD_MEMORY
;
779 if(form
->contenttype
)
780 prevtype
= form
->contenttype
;
786 /* we return on error, free possibly allocated fields */
792 if(form
->value_alloc
)
794 if(form
->contenttype_alloc
)
795 free(form
->contenttype
);
796 if(form
->showfilename_alloc
)
797 free(form
->showfilename
);
801 /* always delete the allocated memory before returning */
803 while(form
!= NULL
) {
804 FormInfo
*delete_form
;
815 * curl_formadd() is a public API to add a section to the multipart formpost.
818 CURLFORMcode
curl_formadd(struct curl_httppost
**httppost
,
819 struct curl_httppost
**last_post
,
824 va_start(arg
, last_post
);
825 result
= FormAdd(httppost
, last_post
, arg
);
831 * AddFormData() adds a chunk of data to the FormData linked list.
833 * size is incremented by the chunk length, unless it is NULL
835 static CURLcode
AddFormData(struct FormData
**formp
,
841 struct FormData
*newform
= (struct FormData
*)
842 malloc(sizeof(struct FormData
));
844 return CURLE_OUT_OF_MEMORY
;
845 newform
->next
= NULL
;
847 if(type
<= FORM_CONTENT
) {
848 /* we make it easier for plain strings: */
850 length
= strlen((char *)line
);
852 newform
->line
= (char *)malloc(length
+1);
855 return CURLE_OUT_OF_MEMORY
;
857 memcpy(newform
->line
, line
, length
);
858 newform
->length
= length
;
859 newform
->line
[length
]=0; /* zero terminate for easier debugging */
862 /* For callbacks and files we don't have any actual data so we just keep a
863 pointer to whatever this points to */
864 newform
->line
= (char *)line
;
866 newform
->type
= type
;
869 (*formp
)->next
= newform
;
876 if(type
!= FORM_FILE
)
877 /* for static content as well as callback data we add the size given
881 /* Since this is a file to be uploaded here, add the size of the actual
883 if(!strequal("-", newform
->line
)) {
885 if(!stat(newform
->line
, &file
)) {
886 *size
+= file
.st_size
;
895 * AddFormDataf() adds printf()-style formatted data to the formdata chain.
898 static CURLcode
AddFormDataf(struct FormData
**formp
,
900 const char *fmt
, ...)
905 vsnprintf(s
, sizeof(s
), fmt
, ap
);
908 return AddFormData(formp
, FORM_DATA
, s
, 0, size
);
912 * Curl_formclean() is used from http.c, this cleans a built FormData linked
915 void Curl_formclean(struct FormData
**form_ptr
)
917 struct FormData
*next
, *form
;
924 next
=form
->next
; /* the following form line */
925 if(form
->type
<= FORM_CONTENT
)
926 free(form
->line
); /* free the line */
927 free(form
); /* free the struct */
929 } while((form
= next
) != NULL
); /* continue */
934 #ifdef CURL_DOES_CONVERSIONS
936 * Curl_formcovert() is used from http.c, this converts any
937 form items that need to be sent in the network encoding.
938 Returns CURLE_OK on success.
940 CURLcode
Curl_formconvert(struct SessionHandle
*data
, struct FormData
*form
)
942 struct FormData
*next
;
949 return CURLE_BAD_FUNCTION_ARGUMENT
;
952 next
=form
->next
; /* the following form line */
953 if(form
->type
== FORM_DATA
) {
954 rc
= Curl_convert_to_network(data
, form
->line
, form
->length
);
955 /* Curl_convert_to_network calls failf if unsuccessful */
959 } while((form
= next
) != NULL
); /* continue */
962 #endif /* CURL_DOES_CONVERSIONS */
966 * Serialize a curl_httppost struct.
967 * Returns 0 on success.
969 int curl_formget(struct curl_httppost
*form
, void *arg
,
970 curl_formget_callback append
)
974 struct FormData
*data
, *ptr
;
976 rc
= Curl_getFormData(&data
, form
, NULL
, &size
);
980 for (ptr
= data
; ptr
; ptr
= ptr
->next
) {
981 if(ptr
->type
== FORM_FILE
) {
986 Curl_FormInit(&temp
, ptr
);
989 nread
= readfromfile(&temp
, buffer
, sizeof(buffer
));
990 if((nread
== (size_t) -1) || (nread
!= append(arg
, buffer
, nread
))) {
994 Curl_formclean(&data
);
997 } while(nread
== sizeof(buffer
));
999 if(ptr
->length
!= append(arg
, ptr
->line
, ptr
->length
)) {
1000 Curl_formclean(&data
);
1005 Curl_formclean(&data
);
1010 * curl_formfree() is an external function to free up a whole form post
1013 void curl_formfree(struct curl_httppost
*form
)
1015 struct curl_httppost
*next
;
1018 /* no form to free, just get out of this */
1022 next
=form
->next
; /* the following form line */
1024 /* recurse to sub-contents */
1026 curl_formfree(form
->more
);
1028 if( !(form
->flags
& HTTPPOST_PTRNAME
) && form
->name
)
1029 free(form
->name
); /* free the name */
1030 if( !(form
->flags
& (HTTPPOST_PTRCONTENTS
|HTTPPOST_CALLBACK
)) &&
1032 free(form
->contents
); /* free the contents */
1033 if(form
->contenttype
)
1034 free(form
->contenttype
); /* free the content type */
1035 if(form
->showfilename
)
1036 free(form
->showfilename
); /* free the faked file name */
1037 free(form
); /* free the struct */
1039 } while((form
= next
) != NULL
); /* continue */
1042 #ifndef HAVE_BASENAME
1044 (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
1047 The basename() function shall take the pathname pointed to by path and
1048 return a pointer to the final component of the pathname, deleting any
1049 trailing '/' characters.
1051 If the string pointed to by path consists entirely of the '/' character,
1052 basename() shall return a pointer to the string "/". If the string pointed
1053 to by path is exactly "//", it is implementation-defined whether '/' or "//"
1056 If path is a null pointer or points to an empty string, basename() shall
1057 return a pointer to the string ".".
1059 The basename() function may modify the string pointed to by path, and may
1060 return a pointer to static storage that may then be overwritten by a
1061 subsequent call to basename().
1063 The basename() function need not be reentrant. A function that is not
1064 required to be reentrant is not required to be thread-safe.
1067 static char *basename(char *path
)
1069 /* Ignore all the details above for now and make a quick and simple
1070 implementaion here */
1074 s1
=strrchr(path
, '/');
1075 s2
=strrchr(path
, '\\');
1078 path
= (s1
> s2
? s1
: s2
)+1;
1089 static char *strippath(const char *fullfile
)
1093 filename
= strdup(fullfile
); /* duplicate since basename() may ruin the
1094 buffer it works on */
1097 base
= strdup(basename(filename
));
1099 free(filename
); /* free temporary buffer */
1101 return base
; /* returns an allocated string! */
1105 * Curl_getFormData() converts a linked list of "meta data" into a complete
1106 * (possibly huge) multipart formdata. The input list is in 'post', while the
1107 * output resulting linked lists gets stored in '*finalform'. *sizep will get
1108 * the total size of the whole POST.
1109 * A multipart/form_data content-type is built, unless a custom content-type
1110 * is passed in 'custom_content_type'.
1113 CURLcode
Curl_getFormData(struct FormData
**finalform
,
1114 struct curl_httppost
*post
,
1115 const char *custom_content_type
,
1118 struct FormData
*form
= NULL
;
1119 struct FormData
*firstform
;
1120 struct curl_httppost
*file
;
1121 CURLcode result
= CURLE_OK
;
1123 curl_off_t size
=0; /* support potentially ENORMOUS formposts */
1125 char *fileboundary
=NULL
;
1126 struct curl_slist
* curList
;
1128 *finalform
=NULL
; /* default form is empty */
1131 return result
; /* no input => no output! */
1133 boundary
= Curl_FormBoundary();
1135 return CURLE_OUT_OF_MEMORY
;
1137 /* Make the first line of the output */
1138 result
= AddFormDataf(&form
, NULL
,
1139 "%s; boundary=%s\r\n",
1140 custom_content_type
?custom_content_type
:
1141 "Content-Type: multipart/form-data",
1148 /* we DO NOT include that line in the total size of the POST, since it'll be
1149 part of the header! */
1156 result
= AddFormDataf(&form
, &size
, "\r\n");
1162 result
= AddFormDataf(&form
, &size
, "--%s\r\n", boundary
);
1166 /* Maybe later this should be disabled when a custom_content_type is
1167 passed, since Content-Disposition is not meaningful for all multipart
1170 result
= AddFormDataf(&form
, &size
,
1171 "Content-Disposition: form-data; name=\"");
1175 result
= AddFormData(&form
, FORM_DATA
, post
->name
, post
->namelength
,
1180 result
= AddFormDataf(&form
, &size
, "\"");
1185 /* If used, this is a link to more file names, we must then do
1186 the magic to include several files with the same field name */
1188 fileboundary
= Curl_FormBoundary();
1190 result
= AddFormDataf(&form
, &size
,
1191 "\r\nContent-Type: multipart/mixed,"
1202 /* If 'showfilename' is set, that is a faked name passed on to us
1203 to use to in the formpost. If that is not set, the actually used
1204 local file name should be added. */
1207 /* if multiple-file */
1209 (!file
->showfilename
)?strippath(file
->contents
):NULL
;
1211 result
= AddFormDataf(&form
, &size
,
1212 "\r\n--%s\r\nContent-Disposition: "
1213 "attachment; filename=\"%s\"",
1215 (file
->showfilename
?file
->showfilename
:
1222 else if(post
->flags
& (HTTPPOST_FILENAME
|HTTPPOST_BUFFER
|
1223 HTTPPOST_CALLBACK
)) {
1224 /* it should be noted that for the HTTPPOST_FILENAME and
1225 HTTPPOST_CALLBACK cases the ->showfilename struct member is always
1226 assigned at this point */
1228 (!post
->showfilename
)?strippath(post
->contents
):NULL
;
1230 result
= AddFormDataf(&form
, &size
,
1231 "; filename=\"%s\"",
1232 (post
->showfilename
?post
->showfilename
:
1241 if(file
->contenttype
) {
1242 /* we have a specified type */
1243 result
= AddFormDataf(&form
, &size
,
1244 "\r\nContent-Type: %s",
1250 curList
= file
->contentheader
;
1252 /* Process the additional headers specified for this form */
1253 result
= AddFormDataf( &form
, &size
, "\r\n%s", curList
->data
);
1256 curList
= curList
->next
;
1259 Curl_formclean(&firstform
);
1265 /* The header Content-Transfer-Encoding: seems to confuse some receivers
1266 * (like the built-in PHP engine). While I can't see any reason why it
1267 * should, I can just as well skip this to the benefit of the users who
1268 * are using such confused receivers.
1271 if(file
->contenttype
&&
1272 !checkprefix("text/", file
->contenttype
)) {
1273 /* this is not a text content, mention our binary encoding */
1274 result
= AddFormDataf(&form
, &size
,
1275 "\r\nContent-Transfer-Encoding: binary");
1281 result
= AddFormDataf(&form
, &size
, "\r\n\r\n");
1285 if((post
->flags
& HTTPPOST_FILENAME
) ||
1286 (post
->flags
& HTTPPOST_READFILE
)) {
1287 /* we should include the contents from the specified file */
1290 fileread
= strequal("-", file
->contents
)?
1291 stdin
:fopen(file
->contents
, "rb"); /* binary read for win32 */
1294 * VMS: This only allows for stream files on VMS. Stream files are
1295 * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
1296 * every record needs to have a \n appended & 1 added to SIZE
1300 if(fileread
!= stdin
) {
1301 /* close the file again */
1303 /* add the file name only - for later reading from this */
1304 result
= AddFormData(&form
, FORM_FILE
, file
->contents
, 0, &size
);
1307 /* When uploading from stdin, we can't know the size of the file,
1308 * thus must read the full file as before. We *could* use chunked
1309 * transfer-encoding, but that only works for HTTP 1.1 and we
1310 * can't be sure we work with such a server.
1314 while((nread
= fread(buffer
, 1, sizeof(buffer
), fileread
)) != 0) {
1315 result
= AddFormData(&form
, FORM_CONTENT
, buffer
, nread
, &size
);
1322 Curl_formclean(&firstform
);
1331 "\n==> Curl_getFormData couldn't open/read \"%s\"\n",
1334 Curl_formclean(&firstform
);
1337 return CURLE_READ_ERROR
;
1341 else if(post
->flags
& HTTPPOST_BUFFER
) {
1342 /* include contents of buffer */
1343 result
= AddFormData(&form
, FORM_CONTENT
, post
->buffer
,
1344 post
->bufferlength
, &size
);
1348 else if(post
->flags
& HTTPPOST_CALLBACK
) {
1349 /* the contents should be read with the callback and the size
1350 is set with the contentslength */
1351 result
= AddFormData(&form
, FORM_CALLBACK
, post
->userp
,
1352 post
->contentslength
, &size
);
1357 /* include the contents we got */
1358 result
= AddFormData(&form
, FORM_CONTENT
, post
->contents
,
1359 post
->contentslength
, &size
);
1363 } while((file
= file
->more
) != NULL
); /* for each specified file for this field */
1365 Curl_formclean(&firstform
);
1371 /* this was a multiple-file inclusion, make a termination file
1373 result
= AddFormDataf(&form
, &size
,
1381 } while((post
= post
->next
) != NULL
); /* for each field */
1383 Curl_formclean(&firstform
);
1388 /* end-boundary for everything */
1389 result
= AddFormDataf(&form
, &size
,
1393 Curl_formclean(&firstform
);
1402 *finalform
=firstform
;
1408 * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
1409 * and resets the 'sent' counter.
1411 int Curl_FormInit(struct Form
*form
, struct FormData
*formdata
)
1414 return 1; /* error */
1416 form
->data
= formdata
;
1423 static size_t readfromfile(struct Form
*form
, char *buffer
,
1427 bool callback
= (bool)(form
->data
->type
== FORM_CALLBACK
);
1430 nread
= form
->fread_func(buffer
, 1, size
, form
->data
->line
);
1433 /* this file hasn't yet been opened */
1434 form
->fp
= fopen(form
->data
->line
, "rb"); /* b is for binary */
1436 return (size_t)-1; /* failure */
1438 nread
= fread(buffer
, 1, size
, form
->fp
);
1440 if(!nread
|| nread
> size
) {
1441 /* this is the last chunk from the file, move on */
1446 form
->data
= form
->data
->next
;
1453 * Curl_FormReader() is the fread() emulation function that will be used to
1454 * deliver the formdata to the transfer loop and then sent away to the peer.
1456 size_t Curl_FormReader(char *buffer
,
1465 form
=(struct Form
*)mydata
;
1467 wantedsize
= size
* nitems
;
1470 return 0; /* nothing, error, empty */
1472 if((form
->data
->type
== FORM_FILE
) ||
1473 (form
->data
->type
== FORM_CALLBACK
)) {
1474 gotsize
= readfromfile(form
, buffer
, wantedsize
);
1477 /* If positive or -1, return. If zero, continue! */
1482 if( (form
->data
->length
- form
->sent
) > wantedsize
- gotsize
) {
1484 memcpy(buffer
+ gotsize
, form
->data
->line
+ form
->sent
,
1485 wantedsize
- gotsize
);
1487 form
->sent
+= wantedsize
-gotsize
;
1492 memcpy(buffer
+gotsize
,
1493 form
->data
->line
+ form
->sent
,
1494 (form
->data
->length
- form
->sent
) );
1495 gotsize
+= form
->data
->length
- form
->sent
;
1499 form
->data
= form
->data
->next
; /* advance */
1501 } while(form
->data
&& (form
->data
->type
< FORM_CALLBACK
));
1502 /* If we got an empty line and we have more data, we proceed to the next
1503 line immediately to avoid returning zero before we've reached the end. */
1509 * Curl_formpostheader() returns the first line of the formpost, the
1510 * request-header part (which is not part of the request-body like the rest of
1513 char *Curl_formpostheader(void *formp
, size_t *len
)
1516 struct Form
*form
=(struct Form
*)formp
;
1519 return 0; /* nothing, ERROR! */
1521 header
= form
->data
->line
;
1522 *len
= form
->data
->length
;
1524 form
->data
= form
->data
->next
; /* advance */
1531 int FormAddTest(const char * errormsg
,
1532 struct curl_httppost
**httppost
,
1533 struct curl_httppost
**last_post
,
1538 va_start(arg
, last_post
);
1539 if((result
= FormAdd(httppost
, last_post
, arg
)))
1540 fprintf (stderr
, "ERROR doing FormAdd ret: %d action: %s\n", result
,
1547 int main(int argc
, argv_item_t argv
[])
1549 char name1
[] = "simple_COPYCONTENTS";
1550 char name2
[] = "COPYCONTENTS_+_CONTENTTYPE";
1551 char name3
[] = "PTRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH";
1552 char name4
[] = "simple_PTRCONTENTS";
1553 char name5
[] = "PTRCONTENTS_+_CONTENTSLENGTH";
1554 char name6
[] = "PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE";
1555 char name7
[] = "FILE1_+_CONTENTTYPE";
1556 char name8
[] = "FILE1_+_FILE2";
1557 char name9
[] = "FILE1_+_FILE2_+_FILE3";
1558 char name10
[] = "ARRAY: FILE1_+_FILE2_+_FILE3";
1559 char name11
[] = "FILECONTENT";
1560 char value1
[] = "value for simple COPYCONTENTS";
1561 char value2
[] = "value for COPYCONTENTS + CONTENTTYPE";
1562 char value3
[] = "value for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH";
1563 char value4
[] = "value for simple PTRCONTENTS";
1564 char value5
[] = "value for PTRCONTENTS + CONTENTSLENGTH";
1565 char value6
[] = "value for PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE";
1566 char value7
[] = "inet_ntoa_r.h";
1567 char value8
[] = "Makefile.b32";
1568 char type2
[] = "image/gif";
1569 char type6
[] = "text/plain";
1570 char type7
[] = "text/html";
1571 int name3length
= strlen(name3
);
1572 int value3length
= strlen(value3
);
1573 int value5length
= strlen(value5
);
1574 int value6length
= strlen(value6
);
1580 struct curl_httppost
*httppost
=NULL
;
1581 struct curl_httppost
*last_post
=NULL
;
1582 struct curl_forms forms
[4];
1584 struct FormData
*form
;
1585 struct Form formread
;
1590 if(FormAddTest("simple COPYCONTENTS test", &httppost
, &last_post
,
1591 CURLFORM_COPYNAME
, name1
, CURLFORM_COPYCONTENTS
, value1
,
1594 if(FormAddTest("COPYCONTENTS + CONTENTTYPE test", &httppost
, &last_post
,
1595 CURLFORM_COPYNAME
, name2
, CURLFORM_COPYCONTENTS
, value2
,
1596 CURLFORM_CONTENTTYPE
, type2
, CURLFORM_END
))
1598 /* make null character at start to check that contentslength works
1602 if(FormAddTest("PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH test",
1603 &httppost
, &last_post
,
1604 CURLFORM_PTRNAME
, name3
, CURLFORM_COPYCONTENTS
, value3
,
1605 CURLFORM_CONTENTSLENGTH
, value3length
,
1606 CURLFORM_NAMELENGTH
, name3length
, CURLFORM_END
))
1608 if(FormAddTest("simple PTRCONTENTS test", &httppost
, &last_post
,
1609 CURLFORM_COPYNAME
, name4
, CURLFORM_PTRCONTENTS
, value4
,
1612 /* make null character at start to check that contentslength works
1615 if(FormAddTest("PTRCONTENTS + CONTENTSLENGTH test", &httppost
, &last_post
,
1616 CURLFORM_COPYNAME
, name5
, CURLFORM_PTRCONTENTS
, value5
,
1617 CURLFORM_CONTENTSLENGTH
, value5length
, CURLFORM_END
))
1619 /* make null character at start to check that contentslength works
1622 if(FormAddTest("PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE test",
1623 &httppost
, &last_post
,
1624 CURLFORM_COPYNAME
, name6
, CURLFORM_PTRCONTENTS
, value6
,
1625 CURLFORM_CONTENTSLENGTH
, value6length
,
1626 CURLFORM_CONTENTTYPE
, type6
, CURLFORM_END
))
1628 if(FormAddTest("FILE + CONTENTTYPE test", &httppost
, &last_post
,
1629 CURLFORM_COPYNAME
, name7
, CURLFORM_FILE
, value7
,
1630 CURLFORM_CONTENTTYPE
, type7
, CURLFORM_END
))
1632 if(FormAddTest("FILE1 + FILE2 test", &httppost
, &last_post
,
1633 CURLFORM_COPYNAME
, name8
, CURLFORM_FILE
, value7
,
1634 CURLFORM_FILE
, value8
, CURLFORM_END
))
1636 if(FormAddTest("FILE1 + FILE2 + FILE3 test", &httppost
, &last_post
,
1637 CURLFORM_COPYNAME
, name9
, CURLFORM_FILE
, value7
,
1638 CURLFORM_FILE
, value8
, CURLFORM_FILE
, value7
, CURLFORM_END
))
1640 forms
[0].option
= CURLFORM_FILE
;
1641 forms
[0].value
= value7
;
1642 forms
[1].option
= CURLFORM_FILE
;
1643 forms
[1].value
= value8
;
1644 forms
[2].option
= CURLFORM_FILE
;
1645 forms
[2].value
= value7
;
1646 forms
[3].option
= CURLFORM_END
;
1647 if(FormAddTest("FILE1 + FILE2 + FILE3 ARRAY test", &httppost
, &last_post
,
1648 CURLFORM_COPYNAME
, name10
, CURLFORM_ARRAY
, forms
,
1651 if(FormAddTest("FILECONTENT test", &httppost
, &last_post
,
1652 CURLFORM_COPYNAME
, name11
, CURLFORM_FILECONTENT
, value7
,
1656 rc
= Curl_getFormData(&form
, httppost
, NULL
, &size
);
1657 if(rc
!= CURLE_OK
) {
1658 if(rc
!= CURLE_READ_ERROR
) {
1659 const char *errortext
= curl_easy_strerror(rc
);
1660 fprintf(stdout
, "\n==> Curl_getFormData error: %s\n", errortext
);
1665 Curl_FormInit(&formread
, form
);
1668 nread
= Curl_FormReader(buffer
, 1, sizeof(buffer
),
1673 fwrite(buffer
, nread
, 1, stdout
);
1676 fprintf(stdout
, "size: ");
1677 fprintf(stdout
, "%" FORMAT_OFF_T
, size
);
1678 fprintf(stdout
, "\n");
1680 fprintf(stdout
, "\n==> %d Test(s) failed!\n", errors
);
1682 fprintf(stdout
, "\nAll Tests seem to have worked (please check output)\n");
1687 #endif /* _FORM_DEBUG */
1689 #else /* CURL_DISABLE_HTTP */
1690 CURLFORMcode
curl_formadd(struct curl_httppost
**httppost
,
1691 struct curl_httppost
**last_post
,
1696 return CURL_FORMADD_DISABLED
;
1699 int curl_formget(struct curl_httppost
*form
, void *arg
,
1700 curl_formget_callback append
)
1705 return CURL_FORMADD_DISABLED
;
1708 void curl_formfree(struct curl_httppost
*form
)
1711 /* does nothing HTTP is disabled */
1714 #endif /* CURL_DISABLE_HTTP */
1716 #if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
1719 * Curl_FormBoundary() creates a suitable boundary string and returns an
1720 * allocated one. This is also used by SSL-code so it must be present even
1721 * if HTTP is disabled!
1723 char *Curl_FormBoundary(void)
1726 static int randomizer
; /* this is just so that two boundaries within
1727 the same form won't be identical */
1730 static const char table16
[]="abcdef0123456789";
1732 retstring
= (char *)malloc(BOUNDARY_LENGTH
+1);
1735 return NULL
; /* failed */
1737 srand((unsigned int)time(NULL
)+randomizer
++); /* seed */
1739 strcpy(retstring
, "----------------------------");
1741 for(i
=strlen(retstring
); i
<BOUNDARY_LENGTH
; i
++)
1742 retstring
[i
] = table16
[rand()%16];
1744 /* 28 dashes and 12 hexadecimal digits makes 12^16 (184884258895036416)
1746 retstring
[BOUNDARY_LENGTH
]=0; /* zero terminate */
1751 #endif /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */