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.
21 * $Id: formdata.c,v 1.3 2007/03/15 19:22:13 andy 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 -I../include formdata.c strequal.c memdebug.c mprintf.c strerror.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"
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"
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"
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 #if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
115 #ifdef HAVE_SYS_STAT_H
116 #include <sys/stat.h>
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 /* It seems RFC1867 defines no Content-Type to default to
285 text/plain so we don't actually need to set this: */
286 contenttype
= HTTPPOST_CONTENTTYPE_DEFAULT
;
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
;
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
);
325 buffer
= (char*)malloc(length
+add
);
327 return NULL
; /* fail */
329 memcpy(buffer
, src
, length
);
331 /* if length unknown do null termination */
333 buffer
[length
] = '\0';
338 /***************************************************************************
342 * Stores a formpost parameter and builds the appropriate linked list.
344 * Has two principal functionalities: using files and byte arrays as
345 * post parts. Byte arrays are either copied or just the pointer is stored
346 * (as the user requests) while for files only the filename and not the
349 * While you may have only one byte array for each name, multiple filenames
350 * are allowed (and because of this feature CURLFORM_END is needed after
351 * using CURLFORM_FILE).
355 * Simple name/value pair with copied contents:
356 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
357 * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
359 * name/value pair where only the content pointer is remembered:
360 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
361 * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
362 * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
364 * storing a filename (CONTENTTYPE is optional!):
365 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
366 * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
369 * storing multiple filenames:
370 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
371 * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
374 * CURL_FORMADD_OK on success
375 * CURL_FORMADD_MEMORY if the FormInfo allocation fails
376 * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
377 * CURL_FORMADD_NULL if a null pointer was given for a char
378 * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
379 * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
380 * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or an error)
381 * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated
382 * CURL_FORMADD_MEMORY if some allocation for string copying failed.
383 * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
385 ***************************************************************************/
388 CURLFORMcode
FormAdd(struct curl_httppost
**httppost
,
389 struct curl_httppost
**last_post
,
392 FormInfo
*first_form
, *current_form
, *form
= NULL
;
393 CURLFORMcode return_value
= CURL_FORMADD_OK
;
394 const char *prevtype
= NULL
;
395 struct curl_httppost
*post
= NULL
;
396 CURLformoption option
;
397 struct curl_forms
*forms
= NULL
;
398 char *array_value
=NULL
; /* value read from an array */
400 /* This is a state variable, that if TRUE means that we're parsing an
401 array that we got passed to us. If FALSE we're parsing the input
402 va_list arguments. */
403 bool array_state
= FALSE
;
406 * We need to allocate the first struct to fill in.
408 first_form
= (FormInfo
*)calloc(sizeof(struct FormInfo
), 1);
410 return CURL_FORMADD_MEMORY
;
412 current_form
= first_form
;
415 * Loop through all the options set. Break if we have an error to report.
417 while (return_value
== CURL_FORMADD_OK
) {
419 /* first see if we have more parts of the array param */
421 /* get the upcoming option from the given array */
422 option
= forms
->option
;
423 array_value
= (char *)forms
->value
;
425 forms
++; /* advance this to next entry */
426 if (CURLFORM_END
== option
) {
427 /* end of array state */
433 /* This is not array-state, get next option */
434 option
= va_arg(params
, CURLformoption
);
435 if (CURLFORM_END
== option
)
442 /* we don't support an array from within an array */
443 return_value
= CURL_FORMADD_ILLEGAL_ARRAY
;
445 forms
= va_arg(params
, struct curl_forms
*);
449 return_value
= CURL_FORMADD_NULL
;
454 * Set the Name property.
456 case CURLFORM_PTRNAME
:
457 #ifdef CURL_DOES_CONVERSIONS
458 /* treat CURLFORM_PTR like CURLFORM_COPYNAME so we'll
459 have safe memory for the eventual conversion */
461 current_form
->flags
|= HTTPPOST_PTRNAME
; /* fall through */
463 case CURLFORM_COPYNAME
:
464 if (current_form
->name
)
465 return_value
= CURL_FORMADD_OPTION_TWICE
;
467 char *name
= array_state
?
468 array_value
:va_arg(params
, char *);
470 current_form
->name
= name
; /* store for the moment */
472 return_value
= CURL_FORMADD_NULL
;
475 case CURLFORM_NAMELENGTH
:
476 if (current_form
->namelength
)
477 return_value
= CURL_FORMADD_OPTION_TWICE
;
479 current_form
->namelength
=
480 array_state
?(long)array_value
:(long)va_arg(params
, long);
484 * Set the contents property.
486 case CURLFORM_PTRCONTENTS
:
487 current_form
->flags
|= HTTPPOST_PTRCONTENTS
; /* fall through */
488 case CURLFORM_COPYCONTENTS
:
489 if (current_form
->value
)
490 return_value
= CURL_FORMADD_OPTION_TWICE
;
493 array_state
?array_value
:va_arg(params
, char *);
495 current_form
->value
= value
; /* store for the moment */
497 return_value
= CURL_FORMADD_NULL
;
500 case CURLFORM_CONTENTSLENGTH
:
501 if (current_form
->contentslength
)
502 return_value
= CURL_FORMADD_OPTION_TWICE
;
504 current_form
->contentslength
=
505 array_state
?(long)array_value
:va_arg(params
, long);
508 /* Get contents from a given file name */
509 case CURLFORM_FILECONTENT
:
510 if (current_form
->flags
!= 0)
511 return_value
= CURL_FORMADD_OPTION_TWICE
;
513 char *filename
= array_state
?
514 array_value
:va_arg(params
, char *);
516 current_form
->value
= strdup(filename
);
517 if(!current_form
->value
)
518 return_value
= CURL_FORMADD_MEMORY
;
520 current_form
->flags
|= HTTPPOST_READFILE
;
521 current_form
->value_alloc
= TRUE
;
525 return_value
= CURL_FORMADD_NULL
;
529 /* We upload a file */
532 char *filename
= array_state
?array_value
:
533 va_arg(params
, char *);
535 if (current_form
->value
) {
536 if (current_form
->flags
& HTTPPOST_FILENAME
) {
538 if ((current_form
= AddFormInfo(strdup(filename
),
539 NULL
, current_form
)) == NULL
)
540 return_value
= CURL_FORMADD_MEMORY
;
543 return_value
= CURL_FORMADD_NULL
;
546 return_value
= CURL_FORMADD_OPTION_TWICE
;
550 current_form
->value
= strdup(filename
);
551 if(!current_form
->value
)
552 return_value
= CURL_FORMADD_MEMORY
;
554 current_form
->flags
|= HTTPPOST_FILENAME
;
555 current_form
->value_alloc
= TRUE
;
559 return_value
= CURL_FORMADD_NULL
;
564 case CURLFORM_BUFFER
:
566 char *filename
= array_state
?array_value
:
567 va_arg(params
, char *);
569 if (current_form
->value
) {
570 if (current_form
->flags
& HTTPPOST_BUFFER
) {
572 if ((current_form
= AddFormInfo(strdup(filename
),
573 NULL
, current_form
)) == NULL
)
574 return_value
= CURL_FORMADD_MEMORY
;
577 return_value
= CURL_FORMADD_NULL
;
580 return_value
= CURL_FORMADD_OPTION_TWICE
;
584 current_form
->value
= strdup(filename
);
585 if(!current_form
->value
)
586 return_value
= CURL_FORMADD_MEMORY
;
589 return_value
= CURL_FORMADD_NULL
;
590 current_form
->flags
|= HTTPPOST_BUFFER
;
595 case CURLFORM_BUFFERPTR
:
596 current_form
->flags
|= HTTPPOST_PTRBUFFER
;
597 if (current_form
->buffer
)
598 return_value
= CURL_FORMADD_OPTION_TWICE
;
601 array_state
?array_value
:va_arg(params
, char *);
603 current_form
->buffer
= buffer
; /* store for the moment */
605 return_value
= CURL_FORMADD_NULL
;
609 case CURLFORM_BUFFERLENGTH
:
610 if (current_form
->bufferlength
)
611 return_value
= CURL_FORMADD_OPTION_TWICE
;
613 current_form
->bufferlength
=
614 array_state
?(long)array_value
:va_arg(params
, long);
617 case CURLFORM_CONTENTTYPE
:
620 array_state
?array_value
:va_arg(params
, char *);
621 if (current_form
->contenttype
) {
622 if (current_form
->flags
& HTTPPOST_FILENAME
) {
624 if ((current_form
= AddFormInfo(NULL
,
626 current_form
)) == NULL
)
627 return_value
= CURL_FORMADD_MEMORY
;
630 return_value
= CURL_FORMADD_NULL
;
633 return_value
= CURL_FORMADD_OPTION_TWICE
;
637 current_form
->contenttype
= strdup(contenttype
);
638 if(!current_form
->contenttype
)
639 return_value
= CURL_FORMADD_MEMORY
;
641 current_form
->contenttype_alloc
= TRUE
;
644 return_value
= CURL_FORMADD_NULL
;
648 case CURLFORM_CONTENTHEADER
:
650 /* this "cast increases required alignment of target type" but
651 we consider it OK anyway */
652 struct curl_slist
* list
= array_state
?
653 (struct curl_slist
*)array_value
:
654 va_arg(params
, struct curl_slist
*);
656 if( current_form
->contentheader
)
657 return_value
= CURL_FORMADD_OPTION_TWICE
;
659 current_form
->contentheader
= list
;
663 case CURLFORM_FILENAME
:
665 char *filename
= array_state
?array_value
:
666 va_arg(params
, char *);
667 if( current_form
->showfilename
)
668 return_value
= CURL_FORMADD_OPTION_TWICE
;
670 current_form
->showfilename
= strdup(filename
);
671 if(!current_form
->showfilename
)
672 return_value
= CURL_FORMADD_MEMORY
;
674 current_form
->showfilename_alloc
= TRUE
;
679 return_value
= CURL_FORMADD_UNKNOWN_OPTION
;
683 if(CURL_FORMADD_OK
== return_value
) {
684 /* go through the list, check for copleteness and if everything is
685 * alright add the HttpPost item otherwise set return_value accordingly */
688 for(form
= first_form
;
691 if ( ((!form
->name
|| !form
->value
) && !post
) ||
692 ( (form
->contentslength
) &&
693 (form
->flags
& HTTPPOST_FILENAME
) ) ||
694 ( (form
->flags
& HTTPPOST_FILENAME
) &&
695 (form
->flags
& HTTPPOST_PTRCONTENTS
) ) ||
698 (form
->flags
& HTTPPOST_BUFFER
) &&
699 (form
->flags
& HTTPPOST_PTRBUFFER
) ) ||
701 ( (form
->flags
& HTTPPOST_READFILE
) &&
702 (form
->flags
& HTTPPOST_PTRCONTENTS
) )
704 return_value
= CURL_FORMADD_INCOMPLETE
;
708 if ( ((form
->flags
& HTTPPOST_FILENAME
) ||
709 (form
->flags
& HTTPPOST_BUFFER
)) &&
710 !form
->contenttype
) {
711 /* our contenttype is missing */
713 = strdup(ContentTypeForFilename(form
->value
, prevtype
));
714 if(!form
->contenttype
) {
715 return_value
= CURL_FORMADD_MEMORY
;
718 form
->contenttype_alloc
= TRUE
;
720 if ( !(form
->flags
& HTTPPOST_PTRNAME
) &&
721 (form
== first_form
) ) {
722 /* copy name (without strdup; possibly contains null characters) */
723 form
->name
= memdup(form
->name
, form
->namelength
);
725 return_value
= CURL_FORMADD_MEMORY
;
728 form
->name_alloc
= TRUE
;
730 if ( !(form
->flags
& HTTPPOST_FILENAME
) &&
731 !(form
->flags
& HTTPPOST_READFILE
) &&
732 !(form
->flags
& HTTPPOST_PTRCONTENTS
) &&
733 !(form
->flags
& HTTPPOST_PTRBUFFER
) ) {
734 /* copy value (without strdup; possibly contains null characters) */
735 form
->value
= memdup(form
->value
, form
->contentslength
);
737 return_value
= CURL_FORMADD_MEMORY
;
740 form
->value_alloc
= TRUE
;
742 post
= AddHttpPost(form
->name
, form
->namelength
,
743 form
->value
, form
->contentslength
,
744 form
->buffer
, form
->bufferlength
,
745 form
->contenttype
, form
->flags
,
746 form
->contentheader
, form
->showfilename
,
751 return_value
= CURL_FORMADD_MEMORY
;
755 if (form
->contenttype
)
756 prevtype
= form
->contenttype
;
762 /* we return on error, free possibly allocated fields */
768 if(form
->value_alloc
)
770 if(form
->contenttype_alloc
)
771 free(form
->contenttype
);
772 if(form
->showfilename_alloc
)
773 free(form
->showfilename
);
777 /* always delete the allocated memory before returning */
779 while (form
!= NULL
) {
780 FormInfo
*delete_form
;
791 * curl_formadd() is a public API to add a section to the multipart formpost.
794 CURLFORMcode
curl_formadd(struct curl_httppost
**httppost
,
795 struct curl_httppost
**last_post
,
800 va_start(arg
, last_post
);
801 result
= FormAdd(httppost
, last_post
, arg
);
807 * AddFormData() adds a chunk of data to the FormData linked list.
809 * size is incremented by the chunk length, unless it is NULL
811 static CURLcode
AddFormData(struct FormData
**formp
,
817 struct FormData
*newform
= (struct FormData
*)
818 malloc(sizeof(struct FormData
));
820 return CURLE_OUT_OF_MEMORY
;
821 newform
->next
= NULL
;
823 /* we make it easier for plain strings: */
825 length
= strlen((char *)line
);
827 newform
->line
= (char *)malloc(length
+1);
828 if (!newform
->line
) {
830 return CURLE_OUT_OF_MEMORY
;
832 memcpy(newform
->line
, line
, length
);
833 newform
->length
= length
;
834 newform
->line
[length
]=0; /* zero terminate for easier debugging */
835 newform
->type
= type
;
838 (*formp
)->next
= newform
;
845 if((type
== FORM_DATA
) || (type
== FORM_CONTENT
))
848 /* Since this is a file to be uploaded here, add the size of the actual
850 if(!strequal("-", newform
->line
)) {
852 if(!stat(newform
->line
, &file
)) {
853 *size
+= file
.st_size
;
862 * AddFormDataf() adds printf()-style formatted data to the formdata chain.
865 static CURLcode
AddFormDataf(struct FormData
**formp
,
867 const char *fmt
, ...)
872 vsnprintf(s
, sizeof(s
), fmt
, ap
);
875 return AddFormData(formp
, FORM_DATA
, s
, 0, size
);
879 * Curl_formclean() is used from http.c, this cleans a built FormData linked
882 void Curl_formclean(struct FormData
**form_ptr
)
884 struct FormData
*next
, *form
;
891 next
=form
->next
; /* the following form line */
892 free(form
->line
); /* free the line */
893 free(form
); /* free the struct */
895 } while ((form
= next
) != NULL
); /* continue */
900 #ifdef CURL_DOES_CONVERSIONS
902 * Curl_formcovert() is used from http.c, this converts any
903 form items that need to be sent in the network encoding.
904 Returns CURLE_OK on success.
906 CURLcode
Curl_formconvert(struct SessionHandle
*data
, struct FormData
*form
)
908 struct FormData
*next
;
915 return CURLE_BAD_FUNCTION_ARGUMENT
;
918 next
=form
->next
; /* the following form line */
919 if (form
->type
== FORM_DATA
) {
920 rc
= Curl_convert_to_network(data
, form
->line
, form
->length
);
921 /* Curl_convert_to_network calls failf if unsuccessful */
925 } while ((form
= next
) != NULL
); /* continue */
928 #endif /* CURL_DOES_CONVERSIONS */
932 * Serialize a curl_httppost struct.
933 * Returns 0 on success.
935 int curl_formget(struct curl_httppost
*form
, void *arg
,
936 curl_formget_callback append
)
940 struct FormData
*data
, *ptr
;
942 rc
= Curl_getFormData(&data
, form
, NULL
, &size
);
946 for (ptr
= data
; ptr
; ptr
= ptr
->next
) {
947 if (ptr
->type
== FORM_FILE
) {
952 Curl_FormInit(&temp
, ptr
);
955 read
= readfromfile(&temp
, buffer
, sizeof(buffer
));
956 if ((read
== (size_t) -1) || (read
!= append(arg
, buffer
, read
))) {
960 Curl_formclean(&data
);
963 } while (read
== sizeof(buffer
));
965 if (ptr
->length
!= append(arg
, ptr
->line
, ptr
->length
)) {
966 Curl_formclean(&data
);
971 Curl_formclean(&data
);
976 * curl_formfree() is an external function to free up a whole form post
979 void curl_formfree(struct curl_httppost
*form
)
981 struct curl_httppost
*next
;
984 /* no form to free, just get out of this */
988 next
=form
->next
; /* the following form line */
990 /* recurse to sub-contents */
992 curl_formfree(form
->more
);
994 if( !(form
->flags
& HTTPPOST_PTRNAME
) && form
->name
)
995 free(form
->name
); /* free the name */
996 if( !(form
->flags
& HTTPPOST_PTRCONTENTS
) && form
->contents
)
997 free(form
->contents
); /* free the contents */
998 if(form
->contenttype
)
999 free(form
->contenttype
); /* free the content type */
1000 if(form
->showfilename
)
1001 free(form
->showfilename
); /* free the faked file name */
1002 free(form
); /* free the struct */
1004 } while ((form
= next
) != NULL
); /* continue */
1007 #ifndef HAVE_BASENAME
1009 (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
1012 The basename() function shall take the pathname pointed to by path and
1013 return a pointer to the final component of the pathname, deleting any
1014 trailing '/' characters.
1016 If the string pointed to by path consists entirely of the '/' character,
1017 basename() shall return a pointer to the string "/". If the string pointed
1018 to by path is exactly "//", it is implementation-defined whether '/' or "//"
1021 If path is a null pointer or points to an empty string, basename() shall
1022 return a pointer to the string ".".
1024 The basename() function may modify the string pointed to by path, and may
1025 return a pointer to static storage that may then be overwritten by a
1026 subsequent call to basename().
1028 The basename() function need not be reentrant. A function that is not
1029 required to be reentrant is not required to be thread-safe.
1032 static char *basename(char *path
)
1034 /* Ignore all the details above for now and make a quick and simple
1035 implementaion here */
1039 s1
=strrchr(path
, '/');
1040 s2
=strrchr(path
, '\\');
1043 path
= (s1
> s2
? s1
: s2
)+1;
1054 static char *strippath(char *fullfile
)
1058 filename
= strdup(fullfile
); /* duplicate since basename() may ruin the
1059 buffer it works on */
1062 base
= strdup(basename(filename
));
1064 free(filename
); /* free temporary buffer */
1066 return base
; /* returns an allocated string! */
1070 * Curl_getFormData() converts a linked list of "meta data" into a complete
1071 * (possibly huge) multipart formdata. The input list is in 'post', while the
1072 * output resulting linked lists gets stored in '*finalform'. *sizep will get
1073 * the total size of the whole POST.
1074 * A multipart/form_data content-type is built, unless a custom content-type
1075 * is passed in 'custom_content_type'.
1078 CURLcode
Curl_getFormData(struct FormData
**finalform
,
1079 struct curl_httppost
*post
,
1080 const char *custom_content_type
,
1083 struct FormData
*form
= NULL
;
1084 struct FormData
*firstform
;
1085 struct curl_httppost
*file
;
1086 CURLcode result
= CURLE_OK
;
1088 curl_off_t size
=0; /* support potentially ENORMOUS formposts */
1090 char *fileboundary
=NULL
;
1091 struct curl_slist
* curList
;
1093 *finalform
=NULL
; /* default form is empty */
1096 return result
; /* no input => no output! */
1098 boundary
= Curl_FormBoundary();
1100 return CURLE_OUT_OF_MEMORY
;
1102 /* Make the first line of the output */
1103 result
= AddFormDataf(&form
, NULL
,
1104 "%s; boundary=%s\r\n",
1105 custom_content_type
?custom_content_type
:
1106 "Content-Type: multipart/form-data",
1113 /* we DO NOT include that line in the total size of the POST, since it'll be
1114 part of the header! */
1121 result
= AddFormDataf(&form
, &size
, "\r\n");
1127 result
= AddFormDataf(&form
, &size
, "--%s\r\n", boundary
);
1131 /* Maybe later this should be disabled when a custom_content_type is
1132 passed, since Content-Disposition is not meaningful for all multipart
1135 result
= AddFormDataf(&form
, &size
,
1136 "Content-Disposition: form-data; name=\"");
1140 result
= AddFormData(&form
, FORM_DATA
, post
->name
, post
->namelength
,
1145 result
= AddFormDataf(&form
, &size
, "\"");
1150 /* If used, this is a link to more file names, we must then do
1151 the magic to include several files with the same field name */
1153 fileboundary
= Curl_FormBoundary();
1155 result
= AddFormDataf(&form
, &size
,
1156 "\r\nContent-Type: multipart/mixed,"
1167 /* If 'showfilename' is set, that is a faked name passed on to us
1168 to use to in the formpost. If that is not set, the actually used
1169 local file name should be added. */
1172 /* if multiple-file */
1174 (!file
->showfilename
)?strippath(file
->contents
):NULL
;
1176 result
= AddFormDataf(&form
, &size
,
1177 "\r\n--%s\r\nContent-Disposition: "
1178 "attachment; filename=\"%s\"",
1180 (file
->showfilename
?file
->showfilename
:
1187 else if((post
->flags
& HTTPPOST_FILENAME
) ||
1188 (post
->flags
& HTTPPOST_BUFFER
)) {
1191 (!post
->showfilename
)?strippath(post
->contents
):NULL
;
1193 result
= AddFormDataf(&form
, &size
,
1194 "; filename=\"%s\"",
1195 (post
->showfilename
?post
->showfilename
:
1204 if(file
->contenttype
) {
1205 /* we have a specified type */
1206 result
= AddFormDataf(&form
, &size
,
1207 "\r\nContent-Type: %s",
1213 curList
= file
->contentheader
;
1215 /* Process the additional headers specified for this form */
1216 result
= AddFormDataf( &form
, &size
, "\r\n%s", curList
->data
);
1219 curList
= curList
->next
;
1222 Curl_formclean(&firstform
);
1228 /* The header Content-Transfer-Encoding: seems to confuse some receivers
1229 * (like the built-in PHP engine). While I can't see any reason why it
1230 * should, I can just as well skip this to the benefit of the users who
1231 * are using such confused receivers.
1234 if(file
->contenttype
&&
1235 !checkprefix("text/", file
->contenttype
)) {
1236 /* this is not a text content, mention our binary encoding */
1237 result
= AddFormDataf(&form
, &size
,
1238 "\r\nContent-Transfer-Encoding: binary");
1244 result
= AddFormDataf(&form
, &size
, "\r\n\r\n");
1248 if((post
->flags
& HTTPPOST_FILENAME
) ||
1249 (post
->flags
& HTTPPOST_READFILE
)) {
1250 /* we should include the contents from the specified file */
1253 fileread
= strequal("-", file
->contents
)?
1254 stdin
:fopen(file
->contents
, "rb"); /* binary read for win32 */
1257 * VMS: This only allows for stream files on VMS. Stream files are
1258 * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
1259 * every record needs to have a \n appended & 1 added to SIZE
1263 if(fileread
!= stdin
) {
1264 /* close the file again */
1266 /* add the file name only - for later reading from this */
1267 result
= AddFormData(&form
, FORM_FILE
, file
->contents
, 0, &size
);
1270 /* When uploading from stdin, we can't know the size of the file,
1271 * thus must read the full file as before. We *could* use chunked
1272 * transfer-encoding, but that only works for HTTP 1.1 and we
1273 * can't be sure we work with such a server.
1277 while ((nread
= fread(buffer
, 1, sizeof(buffer
), fileread
)) != 0) {
1278 result
= AddFormData(&form
, FORM_CONTENT
, buffer
, nread
, &size
);
1285 Curl_formclean(&firstform
);
1294 "\n==> Curl_getFormData couldn't open/read \"%s\"\n",
1297 Curl_formclean(&firstform
);
1300 return CURLE_READ_ERROR
;
1304 else if (post
->flags
& HTTPPOST_BUFFER
) {
1305 /* include contents of buffer */
1306 result
= AddFormData(&form
, FORM_CONTENT
, post
->buffer
,
1307 post
->bufferlength
, &size
);
1313 /* include the contents we got */
1314 result
= AddFormData(&form
, FORM_CONTENT
, post
->contents
,
1315 post
->contentslength
, &size
);
1319 } while ((file
= file
->more
) != NULL
); /* for each specified file for this field */
1321 Curl_formclean(&firstform
);
1327 /* this was a multiple-file inclusion, make a termination file
1329 result
= AddFormDataf(&form
, &size
,
1337 } while ((post
= post
->next
) != NULL
); /* for each field */
1339 Curl_formclean(&firstform
);
1344 /* end-boundary for everything */
1345 result
= AddFormDataf(&form
, &size
,
1349 Curl_formclean(&firstform
);
1358 *finalform
=firstform
;
1364 * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
1365 * and resets the 'sent' counter.
1367 int Curl_FormInit(struct Form
*form
, struct FormData
*formdata
)
1370 return 1; /* error */
1372 form
->data
= formdata
;
1379 static size_t readfromfile(struct Form
*form
, char *buffer
, size_t size
)
1383 /* this file hasn't yet been opened */
1384 form
->fp
= fopen(form
->data
->line
, "rb"); /* b is for binary */
1386 return (size_t)-1; /* failure */
1388 nread
= fread(buffer
, 1, size
, form
->fp
);
1391 /* this is the last chunk from the file, move on */
1394 form
->data
= form
->data
->next
;
1401 * Curl_FormReader() is the fread() emulation function that will be used to
1402 * deliver the formdata to the transfer loop and then sent away to the peer.
1404 size_t Curl_FormReader(char *buffer
,
1413 form
=(struct Form
*)mydata
;
1415 wantedsize
= size
* nitems
;
1418 return 0; /* nothing, error, empty */
1420 if(form
->data
->type
== FORM_FILE
) {
1421 gotsize
= readfromfile(form
, buffer
, wantedsize
);
1424 /* If positive or -1, return. If zero, continue! */
1429 if( (form
->data
->length
- form
->sent
) > wantedsize
- gotsize
) {
1431 memcpy(buffer
+ gotsize
, form
->data
->line
+ form
->sent
,
1432 wantedsize
- gotsize
);
1434 form
->sent
+= wantedsize
-gotsize
;
1439 memcpy(buffer
+gotsize
,
1440 form
->data
->line
+ form
->sent
,
1441 (form
->data
->length
- form
->sent
) );
1442 gotsize
+= form
->data
->length
- form
->sent
;
1446 form
->data
= form
->data
->next
; /* advance */
1448 } while(form
->data
&& (form
->data
->type
!= FORM_FILE
));
1449 /* If we got an empty line and we have more data, we proceed to the next
1450 line immediately to avoid returning zero before we've reached the end.
1451 This is the bug reported November 22 1999 on curl 6.3. (Daniel) */
1457 * Curl_formpostheader() returns the first line of the formpost, the
1458 * request-header part (which is not part of the request-body like the rest of
1461 char *Curl_formpostheader(void *formp
, size_t *len
)
1464 struct Form
*form
=(struct Form
*)formp
;
1467 return 0; /* nothing, ERROR! */
1469 header
= form
->data
->line
;
1470 *len
= form
->data
->length
;
1472 form
->data
= form
->data
->next
; /* advance */
1479 int FormAddTest(const char * errormsg
,
1480 struct curl_httppost
**httppost
,
1481 struct curl_httppost
**last_post
,
1486 va_start(arg
, last_post
);
1487 if ((result
= FormAdd(httppost
, last_post
, arg
)))
1488 fprintf (stderr
, "ERROR doing FormAdd ret: %d action: %s\n", result
,
1497 char name1
[] = "simple_COPYCONTENTS";
1498 char name2
[] = "COPYCONTENTS_+_CONTENTTYPE";
1499 char name3
[] = "PTRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH";
1500 char name4
[] = "simple_PTRCONTENTS";
1501 char name5
[] = "PTRCONTENTS_+_CONTENTSLENGTH";
1502 char name6
[] = "PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE";
1503 char name7
[] = "FILE1_+_CONTENTTYPE";
1504 char name8
[] = "FILE1_+_FILE2";
1505 char name9
[] = "FILE1_+_FILE2_+_FILE3";
1506 char name10
[] = "ARRAY: FILE1_+_FILE2_+_FILE3";
1507 char name11
[] = "FILECONTENT";
1508 char value1
[] = "value for simple COPYCONTENTS";
1509 char value2
[] = "value for COPYCONTENTS + CONTENTTYPE";
1510 char value3
[] = "value for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH";
1511 char value4
[] = "value for simple PTRCONTENTS";
1512 char value5
[] = "value for PTRCONTENTS + CONTENTSLENGTH";
1513 char value6
[] = "value for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE";
1514 char value7
[] = "inet_ntoa_r.h";
1515 char value8
[] = "Makefile.b32";
1516 char type2
[] = "image/gif";
1517 char type6
[] = "text/plain";
1518 char type7
[] = "text/html";
1519 int name3length
= strlen(name3
);
1520 int value3length
= strlen(value3
);
1521 int value5length
= strlen(value4
);
1522 int value6length
= strlen(value5
);
1528 struct curl_httppost
*httppost
=NULL
;
1529 struct curl_httppost
*last_post
=NULL
;
1530 struct curl_forms forms
[4];
1532 struct FormData
*form
;
1533 struct Form formread
;
1535 if (FormAddTest("simple COPYCONTENTS test", &httppost
, &last_post
,
1536 CURLFORM_COPYNAME
, name1
, CURLFORM_COPYCONTENTS
, value1
,
1539 if (FormAddTest("COPYCONTENTS + CONTENTTYPE test", &httppost
, &last_post
,
1540 CURLFORM_COPYNAME
, name2
, CURLFORM_COPYCONTENTS
, value2
,
1541 CURLFORM_CONTENTTYPE
, type2
, CURLFORM_END
))
1543 /* make null character at start to check that contentslength works
1547 if (FormAddTest("PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH test",
1548 &httppost
, &last_post
,
1549 CURLFORM_PTRNAME
, name3
, CURLFORM_COPYCONTENTS
, value3
,
1550 CURLFORM_CONTENTSLENGTH
, value3length
,
1551 CURLFORM_NAMELENGTH
, name3length
, CURLFORM_END
))
1553 if (FormAddTest("simple PTRCONTENTS test", &httppost
, &last_post
,
1554 CURLFORM_COPYNAME
, name4
, CURLFORM_PTRCONTENTS
, value4
,
1557 /* make null character at start to check that contentslength works
1560 if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH test", &httppost
, &last_post
,
1561 CURLFORM_COPYNAME
, name5
, CURLFORM_PTRCONTENTS
, value5
,
1562 CURLFORM_CONTENTSLENGTH
, value5length
, CURLFORM_END
))
1564 /* make null character at start to check that contentslength works
1567 if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE test",
1568 &httppost
, &last_post
,
1569 CURLFORM_COPYNAME
, name6
, CURLFORM_PTRCONTENTS
, value6
,
1570 CURLFORM_CONTENTSLENGTH
, value6length
,
1571 CURLFORM_CONTENTTYPE
, type6
, CURLFORM_END
))
1573 if (FormAddTest("FILE + CONTENTTYPE test", &httppost
, &last_post
,
1574 CURLFORM_COPYNAME
, name7
, CURLFORM_FILE
, value7
,
1575 CURLFORM_CONTENTTYPE
, type7
, CURLFORM_END
))
1577 if (FormAddTest("FILE1 + FILE2 test", &httppost
, &last_post
,
1578 CURLFORM_COPYNAME
, name8
, CURLFORM_FILE
, value7
,
1579 CURLFORM_FILE
, value8
, CURLFORM_END
))
1581 if (FormAddTest("FILE1 + FILE2 + FILE3 test", &httppost
, &last_post
,
1582 CURLFORM_COPYNAME
, name9
, CURLFORM_FILE
, value7
,
1583 CURLFORM_FILE
, value8
, CURLFORM_FILE
, value7
, CURLFORM_END
))
1585 forms
[0].option
= CURLFORM_FILE
;
1586 forms
[0].value
= value7
;
1587 forms
[1].option
= CURLFORM_FILE
;
1588 forms
[1].value
= value8
;
1589 forms
[2].option
= CURLFORM_FILE
;
1590 forms
[2].value
= value7
;
1591 forms
[3].option
= CURLFORM_END
;
1592 if (FormAddTest("FILE1 + FILE2 + FILE3 ARRAY test", &httppost
, &last_post
,
1593 CURLFORM_COPYNAME
, name10
, CURLFORM_ARRAY
, forms
,
1596 if (FormAddTest("FILECONTENT test", &httppost
, &last_post
,
1597 CURLFORM_COPYNAME
, name11
, CURLFORM_FILECONTENT
, value7
,
1601 rc
= Curl_getFormData(&form
, httppost
, NULL
, &size
);
1602 if(rc
!= CURLE_OK
) {
1603 if(rc
!= CURLE_READ_ERROR
) {
1604 const char *errortext
= curl_easy_strerror(rc
);
1605 fprintf(stdout
, "\n==> Curl_getFormData error: %s\n", errortext
);
1610 Curl_FormInit(&formread
, form
);
1613 nread
= Curl_FormReader(buffer
, 1, sizeof(buffer
),
1618 fwrite(buffer
, nread
, 1, stdout
);
1621 fprintf(stdout
, "size: %d\n", size
);
1623 fprintf(stdout
, "\n==> %d Test(s) failed!\n", errors
);
1625 fprintf(stdout
, "\nAll Tests seem to have worked (please check output)\n");
1630 #endif /* _FORM_DEBUG */
1632 #else /* CURL_DISABLE_HTTP */
1633 CURLFORMcode
curl_formadd(struct curl_httppost
**httppost
,
1634 struct curl_httppost
**last_post
,
1639 return CURL_FORMADD_DISABLED
;
1642 int curl_formget(struct curl_httppost
*form
, void *arg
,
1643 curl_formget_callback append
)
1648 return CURL_FORMADD_DISABLED
;
1651 void curl_formfree(struct curl_httppost
*form
)
1654 /* does nothing HTTP is disabled */
1657 #endif /* CURL_DISABLE_HTTP */
1659 #if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
1662 * Curl_FormBoundary() creates a suitable boundary string and returns an
1663 * allocated one. This is also used by SSL-code so it must be present even
1664 * if HTTP is disabled!
1666 char *Curl_FormBoundary(void)
1669 static int randomizer
; /* this is just so that two boundaries within
1670 the same form won't be identical */
1673 static const char table16
[]="abcdef0123456789";
1675 retstring
= (char *)malloc(BOUNDARY_LENGTH
+1);
1678 return NULL
; /* failed */
1680 srand((unsigned int)time(NULL
)+randomizer
++); /* seed */
1682 strcpy(retstring
, "----------------------------");
1684 for(i
=strlen(retstring
); i
<BOUNDARY_LENGTH
; i
++)
1685 retstring
[i
] = table16
[rand()%16];
1687 /* 28 dashes and 12 hexadecimal digits makes 12^16 (184884258895036416)
1689 retstring
[BOUNDARY_LENGTH
]=0; /* zero terminate */
1694 #endif /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */